JSON Parser HTTP Request über WLAN ESP8266

Moin,

ich bin blutiger Anfänger und habe für mein Verhältnis viel vor.

Ich umreiße das Thema mal eben:
Ich habe einen Volkszähler (Datenlogger mit Raumtemperaturen) am laufen.
Über eine API kann man per HTTP Request Daten da rausbekommen in Form eines JSON.
Diese möchte ich über WLAN auf einem ESP8266 einlesen und auf einem TFT Display darstellen.
Und die richtige Zeit und Daum sollen auf dem Display angezeigt werden.
Ich habe noch nie Arduino programmiert :frowning:

Also, Volkszähler läuft - check
HTTP Request und JSON funktioniert, im Browser getestet - check
Arduino IDE läuft - check
Programme aus ESP hochladen läuft - check
TFT Display an ESP angeschlossen - check
Datum und Zeit werden auf dem Display angezeigt - check

Nicht schlecht für jemanden, der noch nie was mit Linux und Arduino gemacht hat, oder?

Nun der nächste Schritt:
Auf dem ESP8266 per WLAN ein HTTP Request machen und das JSON einlesen.
Krieg ich noch nicht ganz hin.
Ich habe mir die Bibliothek ArduinoJson installiert und mir das Beispiel JsonHttpClient angesehen. Leider läuft das über Ethernet. Das muss ich nun auf WLAN umstricken.

Krieg ich aber leider nicht hin.
Wer könnte da mal helfen?

// Sample Arduino Json Web Client
// Downloads and parse http://jsonplaceholder.typicode.com/users/1
//
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
//#include <Ethernet.h>
#include <SPI.h>

//EthernetClient client;

const char WiFiSSID[] = "Chriss 1234";     //### your Router SSID
const char WiFiPSK[]  = "1234567890123456"; //### your Router Password

const char* server = "jsonplaceholder.typicode.com";  // server's address
const char* resource = "/users/1";                    // http resource
const unsigned long BAUD_RATE = 9600;                 // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response

bool isConnected(long timeOutSec) {
  timeOutSec = timeOutSec * 1000;
  int z = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");

    if (z == timeOutSec / 200) { return false; }
    z++;
  }
  return true;
}


// The type of data that we want to extract from the page
struct UserData {
  char name[32];
  char company[32];
  char type[32];
  char color[32];
  char title[32];
};

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
  initSerial();
//  initEthernet();
  WiFi.mode(WIFI_STA);
  WiFi.begin(WiFiSSID, WiFiPSK);
 
  if (isConnected(30)) {
  //  wasConnected = true;
    Serial.println(F("WLAN läuft"));
     }

  
}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
  if (connect(server)) {
    if (sendRequest(server, resource) && skipResponseHeaders()) {
      UserData userData;
      if (readReponseContent(&userData)) {
        printUserData(&userData);
      }
    }
  }
  disconnect();
  wait();
}

// Initialize Serial port
void initSerial() {
  Serial.begin(BAUD_RATE);
  while (!Serial) {
    ;  // wait for serial port to initialize
  }
  Serial.println("Serial ready");
}

/*// Initialize Ethernet library
void initEthernet() {
  byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
  if (!Ethernet.begin(mac)) {
    Serial.println("Failed to configure Ethernet");
    return;
  }
  Serial.println("Ethernet ready");
  delay(1000);
}
*/

// Open connection to the HTTP server
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;
}

// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

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

  return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
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;
}

// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
// {
//   "id": 1,
//   "name": "Leanne Graham",
//   "username": "Bret",
//   "email": "Sincere@april.biz",
//   "address": {
//     "street": "Kulas Light",
//     "suite": "Apt. 556",
//     "city": "Gwenborough",
//     "zipcode": "92998-3874",
//     "geo": {
//       "lat": "-37.3159",
//       "lng": "81.1496"
//     }
//   },
//   "phone": "1-770-736-8031 x56442",
//   "website": "hildegard.org",
//   "company": {
//     "name": "Romaguera-Crona",
//     "catchPhrase": "Multi-layered client-server neural-net",
//     "bs": "harness real-time e-markets"
//   }
// }
bool readReponseContent(struct UserData* userData) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  // See https://bblanchon.github.io/ArduinoJson/assistant/
  const size_t BUFFER_SIZE =
      JSON_OBJECT_SIZE(8)    // the root object has 8 elements
      + JSON_OBJECT_SIZE(5)  // the "address" object has 5 elements
      + JSON_OBJECT_SIZE(2)  // the "geo" object has 2 elements
      + JSON_OBJECT_SIZE(3)  // the "company" object has 3 elements
      + MAX_CONTENT_SIZE;    // additional space for strings

  // Allocate a temporary memory pool
  DynamicJsonBuffer jsonBuffer(BUFFER_SIZE);

  JsonObject& root = jsonBuffer.parseObject(client);

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

  // Here were copy the strings we're interested in
  strcpy(userData->name, root["name"]);
  strcpy(userData->company, root["company"]["name"]);
  // It's not mandatory to make a copy, you could just use the pointers
  // Since, they are pointing inside the "content" buffer, so you need to make
  // sure it's still in memory when you read the string

  return true;
}

// Print the data extracted from the JSON
void printUserData(const struct UserData* userData) {
  Serial.print("Name = ");
  Serial.println(userData->name);
  Serial.print("Company = ");
  Serial.println(userData->company);
}

// Close the connection with the HTTP server
void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}

Danke und lieben Gruß,
Chris

Nimm anstelle von

//EthernetClient client;

den hier:

WiFiClient client;

#include <SPI.h> dürftest Du auch nicht brauchen.

Gruß Tommy

Hammer!

Perfekte Antwort! So liebe ich das :slight_smile:

Nun funktioniert es :slight_smile:

Das SPI.h brauche ich für die Ansteuerung des Displays (…glaube ich :wink:
Das fehlt aber in dem Code.

Nochmals vielen Dank! Nun kann ich weiter herumprobieren :slight_smile:

Danke und lieben Gruß,
Chris

Schön, dass es funktioniert.

Zum Glück haben die Macher der beiden Libs sie nach außen hin weitgehend kompatibel gemacht.

Viel Erfolg mit dem Display.

Gruß Tommy

Hmmmm, tja, ich bin zwar ein ganzes Stück weiter, aber nun habe ich das Problem, dass das JSON nicht geparst wird.

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
WiFiClient client;
const char WiFiSSID[] = "Chriss 123456";     //### your Router SSID
const char WiFiPSK[]  = "1234567890132654"; //### your Router Password
const char* server = "192.168.178.43";  // server's address
const char* resource = "/middleware.php/channel/003321-9654-146-acf4-754654654.json";      // http resource Kanalinfo Temperatur AUSSEN
const unsigned long BAUD_RATE = 9600;                 // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response
bool isConnected(long timeOutSec) {
  timeOutSec = timeOutSec * 1000;  int z = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
    if (z == timeOutSec / 200) { return false; }
    z++;  }  return true;}

// The type of data that we want to extract from the page
struct UserData {
  char name[32];
  char company[32];
  char type[32];
  char color[32];
  char title[32];
};

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
  initSerial();
  WiFi.mode(WIFI_STA);
  WiFi.begin(WiFiSSID, WiFiPSK);
  if (isConnected(30)) {
    Serial.println(F("WLAN läuft"));     }}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
  if (connect(server)) {
    if (sendRequest(server, resource) && skipResponseHeaders()) {
      UserData userData;
      if (readReponseContent(&userData)) {
        printUserData(&userData);
      }
    }
  }
  disconnect();
  wait();
}

// Initialize Serial port
void initSerial() {
  Serial.begin(BAUD_RATE);
  while (!Serial) {
    ;  // wait for serial port to initialize
  }
  Serial.println("Serial ready");
}

// Open connection to the HTTP server
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;
}

// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);
  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.0");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();
  return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
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;
}

// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
// {
//   "id": 1,
//   "name": "Leanne Graham",
//   "username": "Bret",
//   "email": "Sincere@april.biz",
//   "address": {
//     "street": "Kulas Light",
//     "suite": "Apt. 556",
//     "city": "Gwenborough",
//     "zipcode": "92998-3874",
//     "geo": {
//       "lat": "-37.3159",
//       "lng": "81.1496"
//     }
//   },
//   "phone": "1-770-736-8031 x56442",
//   "website": "hildegard.org",
//   "company": {
//     "name": "Romaguera-Crona",
//     "catchPhrase": "Multi-layered client-server neural-net",
//     "bs": "harness real-time e-markets"
//   }
// }

// {
//   "version": "0.3",
//    "entity": {
//      "uuid": "003321-9654-146-acf4-754654654",
//      "type": "temperature",
//      "active": false,
//      "color": "#009933",
//      "fillstyle": 0,
//      "public": true,
//      "style": "lines",
//      "title": "T01 Aussen",
//      "yaxis": "auto"
//    }
// }




bool readReponseContent(struct UserData* userData) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  // See https://bblanchon.github.io/ArduinoJson/assistant/
  const size_t BUFFER_SIZE =
      JSON_OBJECT_SIZE(2)    // the root object has 2 elements
      + JSON_OBJECT_SIZE(9)  // the "entity" object has 5 elements
      + MAX_CONTENT_SIZE;    // additional space for strings

  // Allocate a temporary memory pool
  DynamicJsonBuffer jsonBuffer(BUFFER_SIZE);
  JsonObject& root = jsonBuffer.parseObject(client);
  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  // Here were copy the strings we're interested in
  strcpy(userData->name, root["name"]);
  strcpy(userData->company, root["company"]["name"]);
  // It's not mandatory to make a copy, you could just use the pointers
  // Since, they are pointing inside the "content" buffer, so you need to make
  // sure it's still in memory when you read the string
  return true;
}

// Print the data extracted from the JSON
void printUserData(const struct UserData* userData) {
  Serial.print("Name = ");
  Serial.println(userData->name);
  Serial.print("Company = ");
  Serial.println(userData->company);
}

// Close the connection with the HTTP server
void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}

Als Fehler kommt da folgendes bei raus:

Serial ready
...................................WLAN läuft
Connect to 192.168.178.43
Connected
GET /middleware.php/channel/003321-9654-146-acf4-754654654.json

Exception (28):
epc1=0x4000bf0e epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: cont 
sp: 3ffef9e0 end: 3ffefca0 offset: 01a0

>>>stack>>>
3ffefb80:  3ffe8550 00000000 3fff05a8 402024d5  
3ffefb90:  3ffefba4 3ffeeb28 3ffe0000 3ffefba4  
3ffefba0:  3fffda0a 3ffe8550 3ffeeb28 3fff059c  
3ffefbb0:  00000580 3ffe84d0 3ffeeb28 40201e03  
3ffefbc0:  0a0d0a0d 00000000 3ffeec44 3ffeec70  
3ffefbd0:  3fffdad0 00000000 3ffe836c 40202605  
3ffefbe0:  ffffff00 43ffffff 73697268 39333720  
3ffefbf0:  00000030 00000000 3ffeec44 401004d8  
3ffefc00:  feefeffe 33000001 39303632 33353237  
3ffefc10:  39383534 00000001 3ffe8715 4020391c  
3ffefc20:  401051fc 002266eb 3ffeeb88 3ffeec70  
3ffefc30:  3fffdad0 0000000b 3ffeec44 402032e1  
3ffefc40:  3ffe8714 3ffeec70 40203638 3ffeec80  
3ffefc50:  3ffefddc 0000000a 3ffeec44 4020330c  
3ffefc60:  3fffdad0 00000000 3ffeec44 40203330  
3ffefc70:  3fffdad0 00000000 3ffeeb50 40201d44  
3ffefc80:  feefeffe feefeffe 3ffeec68 40203684  
3ffefc90:  feefeffe feefeffe 3ffeec80 40100718  
<<<stack<<<

Kann da jemand weiterhelfen?

Lieben Dank,
Chris

Hat vielleicht jemand eine Idee was das Problem mit der "Exception (28):" ist?

Ich habe schon viel gesucht, auch viel gefunden, verstehe das Problem aber nicht wirklich und finde daher bisher auch noch keine Lösung :-(

Ich würde mich sehr freuen, wenn mir jemand helfen könnte :-)

Lieben Grüße, Chris

Installiere Dir mal den ExceptionDecoder. Da gibt es mehr Infos.

Gruß Tommy

Moin Tommy,

habe ich runtergeladen. Was fange ich jetzt damit an? Wie benutzt man das?

........ Moment, schon gefunden, bin dran!

Lieben Gruß, Chris

Du erstellst in Deinem -Ordner ein Verzeichnis “tools”. Da hinein entpackst Du das Zip.
Nach dem Neustart der IDE gibt es dann unter Werkzeuge den Eintrag “ESP Exception Decoder”.

Der will wissen, wo das ELF-File Deines Sketches steht. Das erfährst Du, wenn Du die ausführlichen eldungen unter Datei/Einstellungen aktivierst.

Gruß Tommy

Wow, cool:

Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
Decoding 14 results
0x402024d5: get  at C:\Users\Chris\Documents\Arduino\libraries\ArduinoJson\src/ArduinoJson/JsonObject.hpp line 183
:  (inlined by) as  at C:\Users\Chris\Documents\Arduino\libraries\ArduinoJson\src/ArduinoJson/JsonObjectSubscript.hpp line 64
:  (inlined by) as  at C:\Users\Chris\Documents\Arduino\libraries\ArduinoJson\src/ArduinoJson/Deserialization/../JsonVariantBase.hpp line 63
:  (inlined by) operator char const*  at C:\Users\Chris\Documents\Arduino\libraries\ArduinoJson\src/ArduinoJson/Deserialization/../JsonVariantBase.hpp line 58
:  (inlined by) readReponseContent(UserData*) at D:\nodeMCU\Sketch\Chris_JSON_Http_3_VZ\Chris_JSON_Http_3_VZ/Chris_JSON_Http_3_VZ.ino line 157
0x40201e03: skipResponseHeaders() at D:\nodeMCU\Sketch\Chris_JSON_Http_3_VZ\Chris_JSON_Http_3_VZ/Chris_JSON_Http_3_VZ.ino line 89
0x40202605: loop at D:\nodeMCU\Sketch\Chris_JSON_Http_3_VZ\Chris_JSON_Http_3_VZ/Chris_JSON_Http_3_VZ.ino line 43
0x401004d8: malloc at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266\umm_malloc/umm_malloc.c line 1662
0x4020391c: Print::write(unsigned char const*, unsigned int) at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.cpp line 64
0x401051fc: ets_timer_arm_new at ?? line ?
0x402032e1: Print::write(char const*) at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.cpp line 64
0x40203638: esp_yield at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/core_esp8266_main.cpp line 43
0x4020330c: Print::println() at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.cpp line 64
0x40203330: Print::println(__FlashStringHelper const*) at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/Print.cpp line 64
0x40201d44: setup at D:\nodeMCU\Sketch\Chris_JSON_Http_3_VZ\Chris_JSON_Http_3_VZ/Chris_JSON_Http_3_VZ.ino line 36
0x40203684: loop_wrapper at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/core_esp8266_main.cpp line 43
0x40100718: cont_norm at C:\Users\Chris\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.2.0\cores\esp8266/cont.S line 109

Der will wissen, wo das ELF-File Deines Sketches steht. Das erfährst Du, wenn Du die ausführlichen Meldungen unter Datei/Einstellungen aktivierst.

Hmm, da komm ich noch nicht ganz mit. Was ist das ELF File?` Ich hab die ausführlichen Meldungen aktiviert, aber nichts mit "ELF" darin gefunden.

Oder hat sich das jetzt erledigt, weil der Exception Decoder schon läuft?

Lieben Dank! Chris

Doch ziemlich weit unten und etwas nach rechts steht DeinSketchName.ino.elf

z.B. bei mir: "C:\Users\Tommy\AppData\Local\Temp\arduino_build_705189/WSDebug.ino.elf"

Gruß Tommy

Jawoll, ELF File gefunden.

"C:\Users\Chris\AppData\Local\Temp\arduino_build_749056/Chris_JSON_Http_3_VZ.ino.elf"

aber was tue ich jetzt damit? Wer will wissen wo das ELF File ist?

Wenn ich den Exception Decoder starte geht nur ein Fenster auf mit der Meldung "Paste your stack trace here"

Das hatte ich ja schon gemacht und das Ergebnis davon steht in meinem vorletzten Post in diesem Thread: http://forum.arduino.cc/index.php?topic=490474.msg3347519#msg3347519

Aber was sagt mir das jetzt und vor allem wie löse ich das Problem?!

Danke und lieben Gruß, Chris

Du hast ein Speicherproblem. Dein JSON-Objekt kann anscheinend nicht gespeichert werden.

Gruß Tommy

Hmmmm, okay.....und nu? Hardware ist ein nodeMCU ESP12-E mit 4MB

Was ich dabei nicht verstehe ist, das die Beispieldatei mit diesem (längeren) JSON problemlos funktioniert:

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}

und bei folgendem kürzen und weniger verschachteltem JSON bekomme ich ein Speicherproblem?!?!?!:

{
  "version": "0.3",
   "entity": {
     "uuid": "003321-9654-146-acf4-754654654",
     "type": "temperature",
     "active": false,
     "color": "#009933",
     "fillstyle": 0,
     "public": true,
     "style": "lines",
     "title": "T01 Aussen",
     "yaxis": "auto"
   }
}

Das kann doch irgendwie nicht sein?!

Lieben Gruß, Chris

Ich habe nochmal mit der Beispieldatei rumgespielt, das beherrsche ich ohne Probleme.

Langsam kriege ich das Gefühl, das ich mein JSON gar nicht bekomme. Kann ich irgendwie testen, ob ich eine Verbindung zu dem JSON kriege?

Lieben Gruß, Chris

........ich bin auch ein Dödel. Sorry guys for disturbing you!

Fehler gefunden, ich wollte Variablen einlesen, die es in der Beispieldatei gibt, aber nicht in meiner JSON Datei. Die Ausgabezeilen hatte ich editiert, aber nicht die Lesezeilen. Manchmal ist man leider blind. Ich glaube nun läuft es YEAH :-)

Lieben Gruß und vielen Dank für Eure Hilfe und mentale Unterstützung! Chris