首页 > 解决方案 > Arduino 使用 Google Drive Rest API 上传 JPG

问题描述

我编写了一个简单的程序,将 JPG 图像从我的 arduino 上传到 Google Drive。我使用指南中描述的 POST 请求。如果我尝试上传 1600*1200 的图像,有时它可以工作(200),有时不能(308),我不知道为什么。然后,当我收到 308 时,它不会按照指南中的说明将字节范围标头发回给我。

我注意到,如果我正在看电影,响应 308 并且当我停止电影时,过一会儿上传成功

给我带来问题的功能是这个:

bool httpsUploadFromSD(class Token token, String filepath) {
    WiFiSSLClient client = token.getClient();               // I get the client class
    File image = SD.open(filepath, FILE_READ);              // I open the file I want to send

    String name_metadata ="{\"name\": \"" + String(image.name()) + "\"}";
    if (!image) {
        Serial.println("FILE OPEN FAILED");
        return false;
    } else {
        Serial.println("IMAGE OPENED of size" + String(image.size()));
    }


    bool received = false;
    bool trytorefresh = false;
    unsigned long startTime = millis();
    String code = "";
    String uploadID = "";

    // Connecting -- Asking for upload permission
    Serial.println("Asking for upload...");
    do {
        // Sending the upload request
        if (client.connect("www.googleapis.com", 443)) {
            client.println("POST /upload/drive/v3/files?uploadType=resumable HTTP/1.1");
            client.println("Host: www.googleapis.com");
            client.println("Authorization: " + token.token_type + " " + token.access_token);
            client.println("Content-Length: " + String(name_metadata.length()));
            client.println("Content-Type: application/json; charset=UTF-8");
            client.println("X-Upload-Content-Type: image/jpeg");
            client.println("X-Upload-Content-Length: " + String(image.size()));
            client.println("Connection: close");
            client.println();
            client.println(name_metadata);
            client.println();

            Serial.println("Upload request sent");
            received = false;
        } else {
            Serial.println("connection failed");
            received = true;
        }

        //Listen to the client responsse

        while ((millis() - startTime < 5000) && !received) { //try to listen for 5 seconds
            int i = 0;
            while (client.available() && i < 12) {
                received = true;
                char c = client.read();
                Serial.write(c);
                code = code + c;
                i++;
            }

            //When I reckognize 200 I enter here and identify the uploadID;
            if(i>0){
                if (code == "HTTP/1.1 200") {
                    while (client.available()) {
                        char c = client.read(); // here I print in the Serial the response
                        Serial.write(c);
                        if (c == ':') {
                            c = client.read();
                            Serial.write(c);
                            c = client.read();
                            Serial.write(c);
                            do {
                                uploadID = uploadID + c;  // Here I identify UploadID from the resp
                                c = client.read();
                                Serial.write(c);
                            } while (c != '\n');
                            break;
                        }

                    }
                    break;
                }
                else if (code == "HTTP/1.1 401") {
                    while(client.available()) {
                        char c = client.read();
                        Serial.write(c);
                    }
                    // If credentials are not valide, I'll try once to refresh the token;
                    if(!trytorefresh){
                        Serial.println("\nProbably you need to refresh the token\nI'm trying to refresh\n");
                        token.httpsTokenRefresh();
                        trytorefresh = !trytorefresh;
                    }
                }
                else if (code == "HTTP/1.1 400") {
                    while(client.available()) {
                        char c = client.read();
                        Serial.write(c);
                    }
                    break;
                } else {
                    break;
                }
            }

        }
    } while (trytorefresh); // I try to refresh once if the resposnse is 401

    if (code == "HTTP/1.1 200") {
        // I stop the previous client session, because now I start a new one, to do the PUT request and upload the file
        client.stop();
        Serial.println("Token request has been succesful. Starting upload");

        bool succesful = false;

        // I have obtained the uploadID, now I start uploading
        String location = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&upload_id=" + uploadID;
        while(!succesful){                              // I upload until it is successful

            // Upload request
            if (client.connect("www.googleapis.com", 443)) {
                client.println("PUT " + location + " HTTP/1.1");
                client.println("User-Agent: Arduino Camera");
                client.println("Content-Length: "  + String(image.size()));
                client.println("Connecion: close");
                client.println();
                while (image.available()) {
                    client.write(image.read());         // Here I send the bytes of the image
                }

                image.close();
                received = false;
            } else {
                Serial.println("Connection failed");
                received = true;
            }

            // Listening to the response
            startTime = millis();
            String code = "";
            while ((millis() - startTime < 5000) && !received) { //try to listen for 5 seconds
                int i = 0;
                while (client.available() && i < 12) {
                    received = true;
                    char c = client.read();
                    Serial.write(c);
                    code = code + c;
                    i++;
                }

                // HTTP 200 OK
                if (code == "HTTP/1.1 200" || code == "HTTP/1.1 201")
                {
                    while(client.available()) {
                        char c = client.read();
                        Serial.write(c);
                    }
                    Serial.println("\n\nUpload succesful");
                    succesful = true;
                    client.stop();
                    return succesful;

                }

                // HTTP 308 I have to restart my upload

                else if (code == "HTTP/1.1 308") {

                    // Here I print the response in serial and I identify the range to re-send. Actually it always happens that the range header is not present, so I re-send the whole image
                    bool range_present = false;
                    char Range[] = "xxxxxx";
                    String byte_range = "";
                    uint32_t re_send_length = 0;


                    while (client.available()) {
                        for (int k = 0; k<5; k++){
                            Range[k] = Range[k++];
                        }
                        char c = client.read();
                        Range[5] = c;
                        Serial.write(c);

                        if (Range == "Range:") {
                            break;
                            range_present = true;
                        }

                    }

                    if (range_present) {
                        int k = 0;
                        while (client.available() && k<7) {
                            char c = client.read();
                            Serial.write(c);
                        }
                        k = 0;
                        String Range2 = "";
                        while (client.available()) {
                            char c = client.read();
                            Serial.write(c);
                            if (c == '\n') {
                                break;
                            }
                            Range2 = Range2 + c;
                        }
                        while (client.available()) {
                            char c = client.read();
                            Serial.write(c);
                        }

                        bool a = false;
                        for (k = 0; k<Range2.length(); k++) {

                            if (a) {
                                byte_range = byte_range + Range2[k];
                            }

                            if (Range2[k] = '-') {
                                a = true;
                            }
                        }

                        Serial.println("byte_range = " + byte_range);

                    }

                    Serial.println("\n\nUpload interrupted. Starting a new session");

                    // I have to open image again
                    image = SD.open(filepath, FILE_READ);
                    delay(1000);
                }
            }
        }

    } else if (code == "HTTP/1.1 401" && trytorefresh) {
        Serial.println("Upload failed. Probably you need a new token");
    }

    client.stop();
    return false;
}

这里有令牌类

    class TokenRequestData {
public:
    TokenRequestData();
    TokenRequestData(String deviceCode, String userCode, int expiresIn, int Interval, String verificationUrl, WiFiSSLClient Client);

    String device_code;
    String user_code;
    int expires_in;
    int interval;
    String verification_url;
    WiFiSSLClient client;

    void httpsAskForTokenData();

};


class Token {
    TokenRequestData data;
    void httpsTokenPolling(class TokenRequestData requestData);
public:
    Token();
    Token(class TokenRequestData Data, String AccessToken, String RefreshToken, int ExpiresIn);

    String access_token;
    String refresh_token;
    int expires_in;
    String token_type;

    void httpsTokenRequest(class TokenRequestData requestData);
    void httpsTokenRefresh();
    WiFiSSLClient getClient();
};

标签: arduinogoogle-drive-apiarduino-mkr1000

解决方案


推荐阅读