I tried to upload an image (JPG) from an Arduino to Google drive using the API.
Sometimes it works (I do the POST request as described in the guide and send all the bits) and I receive 200 OK, but sometimes, after sending all the bytes, google drive does not give me any response.
any suggestions?
Here there is the part of the code which dose the Upload (note I pasted only the "problematic" part).
- Sometimes the while cycle finishes because I receive the 200 response.
- Sometimes I receive no response and so I start again to send the image.
In
while (millis() - startTime < 15000 && !received)
I tried to wait up to ten minutes, but no response
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;
received = true;
while(!succesful){ // I upload until it is successful
// I stop the previous client session, because now I start a new one, to do the PUT request and upload the file
client.stop();
// 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("Connection: close");
client.println();
while (image.available()) {
client.write(image.read()); // Here I send the bytes of the image
}
Serial.println(".");
image.close();
received = false;
} else {
Serial.println("Connection failed");
received = true;
}
// Listening to the response
startTime = millis();
String code = "";
while (millis() - startTime < 15000 && !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("\nUpload succesful");
succesful = true;
// client.stop();
return succesful;
}
if (!received) {
client.stop();
Serial.println("\nUpload interrupted. Starting a new session");
// I have to open image again
image = SD.open(filepath, FILE_READ);
}
}
Related
I have written a simple program to upload a JPG image from my arduino to Google Drive.
I use a POST request as described in the guide.
If I try to upload a 1600*1200 image, sometimes it works (200) and sometimes not (308) and I can't figure out why.
Then, when I receive 308 it does not send me back the byte range header as described in the guide.
I noticed that if I'm watching a film the response 308 and when I stop the film, after a while the upload becomes successful
The function which is giving me issues is this one:
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;
}
Here there is the token class
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();
};
I am writing a code with arduino and ethernet shield. It consist in an accelerometer which reads values and shows them in a web page. It is in local. If I had to write CSS style with client.print(); I would spend a lot of time and useless lines of code. I would like to add an external CSS sheet linked with the internal page made-up into the arduino sketch. I tried to put the CSSsheet into a directory of the sketch and set <link href> but it didn't work. The page is made like this:
#mike
this is the whole function, thanks.
void RichiesteAlServer() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
//client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
client.println("<head><title>Sismografo</title><link href=\"css/style.css\" rel=\"stylesheet\" type=\"text/css\"/></head>");
client.println("<body>");
client.println("<h1>Sismografo</h1>");
client.println("<p>");
client.print("Indice Array : ");
client.print(indiceArray);
client.println("</p>");
client.println("<p>");
stampaCanvas(client);
client.println("</p>");
client.println("<p>");
client.print("valore: ");
client.print(arrayValoriAccel[indiceArray]);
client.println("</p>");
client.println("<p>");
client.print("inizio scossa : ");
client.print(inizio_scossa);
client.println("</p>");
client.println("<p>");
client.print("fine scossa : ");
client.print(fine_scossa);
client.println("</p>");
client.println("<p>");
client.print("Durata scossa : ");
client.print(durata_totale_scossa);
client.println("</p>");
client.println("<p>");
client.print("cont : ");
client.print(cont);
client.println("</p>");
client.println("</body>");
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
To begin with, I'm doing a mini project on the verification of RFID card using NodeMCU. I set up a database and a server to handle all the requests from the client. The problem is, whenever I try to verify a valid card, the function that handles it keeps returning the wrong value.
To be clear, here is my main loop:
void loop() {
connectToHost();
key = kpd.getKey();
card = readCard();
delay(200);
//check for card status
if(verifyCard(card)){
Serial.println("Card is valid");
} else {
Serial.println("Invalid Card");
}
//check connection status
if(WiFi.status() == WL_CONNECTION_LOST){
connectToWiFi();
}
}
The main loop calls this function:
boolean verifyCard(String uid){
String url = "/ECafe/terminal_verify.php?uid=";
url += uid;
// This will send the request to the server
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
}
yield();
}
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\r');
//if string contains echo from php file
if(line.indexOf("Valid")>0){
return true;
} else {
return false;
}
yield();
}
Serial.println();
Serial.println("Closing connection");
}
I intentionally put a valid card UID in the database just to test this function. Yet, it keeps returning false. I'm sure that the response from the server is "Valid". I suspect that the function doesn't even wait for the response from the server and returns a false value because the interval between the GET request is sent and the response is returned is too short. Is that because of the if condition in the main loop? See the attachment for the serial monitor output.
The logic of your function is flawed.
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\r');
//if string contains echo from php file
if(line.indexOf("Valid")>0){
return true;
} else {
return false;
When the code reads the first line, and it doesn't contain Valid, it will fail and return false. So your code will ALWAYS return false, as I doubt that the first line returned is Valid...
}
yield();
}
Serial.println();
Serial.println("Closing connection");
The rest of this code is never executed. "Closing connection" is never printed right?
I am using an ESP8266 Thing Dev board configured as an access point and server to store data from temperature sensors.
The goal is to access this data with an Android application, but for now, the client used is my computer running Chrome.
The sensors provide new temperatures every 250 ms, which are added to a string (JSON formatted).
When the client requests the data, the string is ended (closing JSON structure), and printed on the server.
The client should be able to access up to 2*50 values at a time. However, each time a request is send, either only 2 or 4 values are printed, either the page is not working.
My Arduino code, using ESP8266 and TMP102 libraries for arduino :
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Ticker.h>
#include "tmp102.h"
#define NB_MAX_TEMP 50
#define MAX_INPUT 20
const byte sensorAddress1 = 0x90; // ADD0 -> GND
const byte sensorAddress2 = 0x92; // ADD0 -> V+
tmp102 *thermometer1 = new tmp102(&Wire);
tmp102 *thermometer2 = new tmp102(&Wire);
// Timer
Ticker ticker;
bool flag = false;
// Wifi
const char WiFiAPPSK[] = "sparkfun"; // Wifi password
WiFiServer server(80);
int count = 0;
String s;
void setupWiFi()
{
WiFi.mode(WIFI_AP);
// Do a little work to get a unique-ish name. Append the
// last two bytes of the MAC (HEX'd) to "ThingDev-":
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = "ThingDev-" + macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
AP_NameChar[i] = AP_NameString.charAt(i);
WiFi.softAP(AP_NameChar, WiFiAPPSK);
}
void timer_done()
{
flag = true;
}
void acquire()
{
int temp1 = 0, temp2 = 0;
if (thermometer1->readTemp(temp1))
{
// If we're reading pins, print out those values:
// first temp
s += String(temp1 * 0.0625);
}
s += ",";
if (thermometer2->readTemp(temp2))
{
// If we're reading pins, print out those values:
// second temp
s += String(temp2 * 0.0625);
}
return;
}
void setup()
{
Wire.begin(); // start the I2C library
Serial.begin(115200);
thermometer1->init(sensorAddress1);
thermometer2->init(sensorAddress2);
//Set default config.
thermometer1->writeConf(TMP102_DEFAULT_CONF);
thermometer2->writeConf(TMP102_DEFAULT_CONF);
setupWiFi();
server.begin();
// timer every 0.25s
ticker.attach(0.25, timer_done);
}
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
if (flag) {
flag = false;
int temp1 = 0, temp2 = 0;
if (count == 0) {
// prepare string
s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: text/html\r\n\r\n";
s += "{temp:[";
}
delay(1);
// add a measurement
s += "[";
acquire();
s += "],";
count += 1;
if (count == NB_MAX_TEMP) {
// Prevent the string to become infinite
count = 0;
s = s.substring(0, s.length() - 1);
s += "]};";
}
}
if (client.available() > 0) {
// Read the first line of the request
String req = client.readStringUntil('\r');
client.flush();
Serial.println(req);
if (req.indexOf("/read") != -1) {
// End the string
s.setCharAt(s.length() - 1, '\0');
s += "]};";
client.print(s);
Serial.println(s);
count = 0;
}
}
delay(1);
Serial.println("Client disconnected");
// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}
And a sample of what I get on the Serial console (the JSON string is the same I read on the server page) :
GET /read HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
{temp:[[24.00,24.56],[24.00,24.56];
Client disconnected
GET /favicon.ico HTTP/1.1
Client disconnected
GET /read HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
{temp:[[24.00,24.56];
Client disconnected
What am I doing wrong ? Am I using a blocking function ? Are the /favicon.ico requests causing trouble ?
For information, the access point part, and the sensor part of my code have been tested separately and work as expected.
Thanks in advance.
Hi i have been trying to send data from my arduino to my ASP.Net website and have been successful until i try to send a timestamp as a variable in the GET request. I have think it has somthing to do with the forward slash that separates the values but when i send a diffrent symbol like a "-" i get the same result (no data saved)
EDIT: sorry its not the forward slash! it is because asp.net expects: 01/01/01 01:01:01 and am sending 1/1/1 1:1:1. so i need to figure out how send it with the zero in front if needed
my code so far (the sending part)
void sendLightData() {
DateTime now = rtc.now();
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
// try to congifure using IP address instead of DHCP:
Ethernet.begin(mac, ip);
}
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected");
// Make a HTTP request:
client.print("GET /LightData.aspx?uname=");
client.print(userName);
client.print("&pword=");
client.print(password);
client.print("&LStatus=");
client.print(lightStatus);
client.print("&LHeight=9&");
client.print("timestamp=");
client.print(now.day(), DEC);
client.print("/");
client.print(now.month(), DEC);
client.print("/");
client.print(now.year(), DEC);
client.print("%20");
client.print(now.hour(), DEC);
client.print(":");
client.print(now.minute(), DEC);
client.print(":");
client.print(now.second(), DEC);
client.println(" HTTP/1.1");
client.println("Host: www.auntieagie.eu");
client.println("Connection: close");
client.println();
// this works if entered into a browser (trying to replicate in arduino) http://auntieagie.eu/LightData.aspx?uname=test&pword=t&LStatus=1&LHeight=2×tamp=21/02/2014%2001:01:01
}
any help or a point in the right direction would be great
you need to url encode things like /
ie
%2F
so 27/2/2014 would be 27%2F2%2F2014
Just URL encode the whole date:
...
client.print("timestamp=");
client.print(URLEncode(String(now)));
...
Helper method:
/**
* URL Encode a string.
*
* Based on http://www.icosaedro.it/apache/urlencode.c
*
*/
String URLEncode(const char* msg)
{
const char *hex = "0123456789abcdef";
String encodedMsg = "";
while (*msg!='\0'){
if( ('a' <= *msg && *msg <= 'z')
|| ('A' <= *msg && *msg <= 'Z')
|| ('0' <= *msg && *msg <= '9') ) {
encodedMsg += *msg;
} else {
encodedMsg += '%';
encodedMsg += hex[*msg >> 4];
encodedMsg += hex[*msg & 15];
}
msg++;
}
return encodedMsg;
}