Search code examples
jsonarduinoesp32arduinojson

Can't get data from Googlesheet using esp32 and Arduinojson


I'm new to esp32 and now I'm trying to Get data using ArduinoJson, In my googlesheet "A1" have a number and I want to let esp32 to get it, I send my googlesheet to internet and use the url:https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1. and my number is at object > feed > entry > 0 > content > $t.

Here's a problem:When I use esp32 to get this json data,I can't get it,even my esp32 connected to googlesheet

Here is my full code if you need:

#include <ArduinoJson.h>
#include <WiFi.h>
#include <SPI.h>

WiFiClient client;

const char* ssid = "wwwwwwwww";
const char* password = "wwwwwwww";
const char* server = "spreadsheets.google.com";
const char* resource = "/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";


const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 1024;       // max size of the HTTP response

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

struct clientData {
  char item[8];
};


void setup() {
  Serial.begin(9600);
  while (!Serial) {

  }
  Serial.println("Serial ready");
  Serial.print("Connecting to wifi: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


void loop() {
  if(connect(server)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      clientData clientData;
      if(readReponseContent(&clientData)) {
        printclientData(&clientData);
      }
    }
  }
  disconnect();
  wait();
}


bool connect(const char* hostName) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, 80);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}


bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();

  return true;
}

bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}


bool readReponseContent(struct clientData* clientData) {
  const size_t bufferSize = 5*JSON_ARRAY_SIZE(1) + 
  JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) + 
  6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) + 
  JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15);
  DynamicJsonBuffer jsonBuffer(bufferSize);

  JsonObject& root = jsonBuffer.parseObject(client);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  strcpy(clientData->item, root["feed"]["entry"][0]["content"]["$t"]);

  return true;
}


void printclientData(const struct clientData* clientData) {
  Serial.print("Time = ");
  Serial.println(clientData->item);

}

void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

void wait() {
  Serial.println("Wait 20 seconds");
  delay(20000);
}

Serial Output:

Connecting to wifi: wwwwwwwwww
..
WiFi connected
IP address: 
xxx.xxx.x.xx
Connect to spreadsheets.google.com
Connected
GET /feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1
JSON parsing failed!
Disconnect
Wait 20 seconds


Solution

  • If I based on your json output and calculate the bufferSize using ArduinoJson Assistant, I get this:

    const size_t capacity = 5*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) + 6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15) + 2270;
    

    Noticed the + 2270 at the end? Your parsing json failed because your are short of 2270 bytes in bufferSize (i.e. your bufferSize is too small).

    Updte

    I didn't try to debug your code, but I have my web client code handy with me so I just run and it works for me.

    My code is based on HTTPClient which is part of ESP32 Arduino Core that you can further read about it at ESP-Arduino github. It is based on Arduino WifiClient that you used but with much simpler and easy to use API, especially for getting response payload. I would recommend you take a look.

    I add ArduinoJson to my code to see if there is any issue on parsing the received json, but mines is based on v6 syntax, you can convert it to v5 syntax if you still feel it is easier for you to use v5. BTW, the json document contains Unicode, I have to add #define ARDUINOJSON_DECODE_UNICODE 1 on the top of the program in oder to make it work, otherwise I will get an deserialization error: NotSupported.

    #define ARDUINOJSON_DECODE_UNICODE 1
    #include <ArduinoJson.h>
    #include <WiFi.h>
    #include <HTTPClient.h>
    
    HTTPClient http;
    
    const char* ssid = "your_SSID";
    const char* password = "your_password";
    
    const char* url = "https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";
    
    void setup() {
      Serial.begin(115200);
      while (!Serial) {}
    
      Serial.print("Connecting to wifi: "); Serial.print(ssid);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(200);
        Serial.print(".");
      }
      Serial.println();
      Serial.print("IP address: "); Serial.println(WiFi.localIP());
    
      http.begin(url); 
      int httpCode = http.GET();  //send GET request
    
      if (httpCode != 200) {
        Serial.print("Error on HTTP request: ");
        Serial.println(httpCode);
      } else {
        String payload = http.getString();
        Serial.println(payload);
    
        // the following is based on ArduinoJson v6 API
        StaticJsonDocument<4000> doc;
        DeserializationError err = deserializeJson(doc, payload);
        if (err) {
          Serial.print("deserialization error ");
          Serial.println(err.c_str());
        }
    
        JsonObject feed = doc["feed"];
        const char* clientData = feed["entry"][0]["content"]["$t"];
        Serial.println(clientData);
      }
    
      http.end(); //Free the resources
    
    }
    
    
    void loop() {
    
    }