|
|
@@ -1,181 +1,86 @@
|
|
|
-// Sample Arduino Json Web Client
|
|
|
-// Downloads and parse http://jsonplaceholder.typicode.com/users/1
|
|
|
-//
|
|
|
// ArduinoJson - arduinojson.org
|
|
|
// Copyright Benoit Blanchon 2014-2017
|
|
|
// MIT License
|
|
|
+//
|
|
|
+// Example of an HTTP client parsing a JSON response.
|
|
|
+//
|
|
|
+// This program perform an HTTP GET of arduinojson.org/example.json
|
|
|
+// Here is the expected response:
|
|
|
+// {
|
|
|
+// "sensor": "gps",
|
|
|
+// "time": 1351824120,
|
|
|
+// "data": [
|
|
|
+// 48.756080,
|
|
|
+// 2.302038
|
|
|
+// ]
|
|
|
+// }
|
|
|
+// See http://arduinojson.org/assistant/ to compute the size of the buffer.
|
|
|
+//
|
|
|
+// Disclaimer: the code emphasize the communication between client and server,
|
|
|
+// it doesn't claim to be a reference of good coding practices.
|
|
|
|
|
|
#include <ArduinoJson.h>
|
|
|
#include <Ethernet.h>
|
|
|
#include <SPI.h>
|
|
|
|
|
|
-EthernetClient client;
|
|
|
-
|
|
|
-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
|
|
|
-
|
|
|
-// The type of data that we want to extract from the page
|
|
|
-struct UserData {
|
|
|
- char name[32];
|
|
|
- char company[32];
|
|
|
-};
|
|
|
-
|
|
|
-// ARDUINO entry point #1: runs once when you press reset or power the board
|
|
|
void setup() {
|
|
|
- initSerial();
|
|
|
- initEthernet();
|
|
|
-}
|
|
|
+ Serial.begin(9600);
|
|
|
+ while (!Serial);
|
|
|
|
|
|
-// 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() {
|
|
|
+ echo("Initialize Ethernet library");
|
|
|
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
|
|
- if (!Ethernet.begin(mac)) {
|
|
|
- Serial.println("Failed to configure Ethernet");
|
|
|
- return;
|
|
|
- }
|
|
|
- Serial.println("Ethernet ready");
|
|
|
+ Ethernet.begin(mac) || die("Failed to configure Ethernet");
|
|
|
delay(1000);
|
|
|
-}
|
|
|
|
|
|
-// Open connection to the HTTP server
|
|
|
-bool connect(const char* hostName) {
|
|
|
- Serial.print("Connect to ");
|
|
|
- Serial.println(hostName);
|
|
|
+ echo("Connect to HTTP server");
|
|
|
+ EthernetClient client;
|
|
|
+ client.setTimeout(10000);
|
|
|
+ client.connect("arduinojson.org", 80) || die("Connection failed");
|
|
|
|
|
|
- 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);
|
|
|
+ echo("Send HTTP request");
|
|
|
+ client.println("GET /example.json HTTP/1.0");
|
|
|
+ client.println("Host: arduinojson.org");
|
|
|
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!");
|
|
|
+ client.println() || die("Failed to send request");
|
|
|
+
|
|
|
+ echo("Check HTTP status");
|
|
|
+ char status[32] = {0};
|
|
|
+ client.readBytesUntil('\r', status, sizeof(status));
|
|
|
+ if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
|
|
|
+ echo(status);
|
|
|
+ die("Unexpected HTTP 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 http://arduinojson.org/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
|
|
|
+ echo("Skip HTTP headers");
|
|
|
+ char endOfHeaders[] = "\r\n\r\n";
|
|
|
+ client.find(endOfHeaders) || die("Invalid response");
|
|
|
|
|
|
- // Allocate a temporary memory pool
|
|
|
+ echo("Allocate JsonBuffer");
|
|
|
+ const size_t BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
|
|
|
DynamicJsonBuffer jsonBuffer(BUFFER_SIZE);
|
|
|
|
|
|
+ echo("Parse JSON object");
|
|
|
JsonObject& root = jsonBuffer.parseObject(client);
|
|
|
+ if (!root.success()) die("Parsing failed!");
|
|
|
|
|
|
- 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
|
|
|
+ echo("Extract values");
|
|
|
+ echo(root["sensor"].as<char*>());
|
|
|
+ echo(root["time"].as<char*>());
|
|
|
+ echo(root["data"][0].as<char*>());
|
|
|
+ echo(root["data"][1].as<char*>());
|
|
|
|
|
|
- return true;
|
|
|
+ echo("Disconnect");
|
|
|
+ client.stop();
|
|
|
}
|
|
|
|
|
|
-// 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);
|
|
|
-}
|
|
|
+void loop() {}
|
|
|
|
|
|
-// Close the connection with the HTTP server
|
|
|
-void disconnect() {
|
|
|
- Serial.println("Disconnect");
|
|
|
- client.stop();
|
|
|
+void echo(const char* message) {
|
|
|
+ Serial.println(message);
|
|
|
}
|
|
|
|
|
|
-// Pause for a 1 minute
|
|
|
-void wait() {
|
|
|
- Serial.println("Wait 60 seconds");
|
|
|
- delay(60000);
|
|
|
-}
|
|
|
+bool die(const char* message) {
|
|
|
+ Serial.println(message);
|
|
|
+ while (true); // loop forever
|
|
|
+ return false;
|
|
|
+}
|