diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c9997c..27b6ac9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ArduinoJson: change log ======================= +HEAD +---- +* Rewrote example `JsonHttpClient.ino` (issue #600) + v5.11.2 ------- @@ -45,20 +49,20 @@ v5.10.0 ### BREAKING CHANGES :warning: | Old syntax | New syntax | -|---------------------------------|---------------------| +|:--------------------------------|:--------------------| | `double_with_n_digits(3.14, 2)` | `3.14` | | `float_with_n_digits(3.14, 2)` | `3.14f` | | `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` | | `arr.add(3.14, 2)` | `arr.add(3.14)` | | Input | Old output | New output | -|-----------|------------|------------| +|:----------|:-----------|:-----------| | `3.14159` | `3.14` | `3.14159` | | `42.0` | `42.00` | `42` | | `0.0` | `0.00` | `0` | | Expression | Old result | New result | -|--------------------------------|------------|------------| +|:-------------------------------|:-----------|:-----------| | `JsonVariant(42).is()` | `true` | `true` | | `JsonVariant(42).is()` | `false` | `true` | | `JsonVariant(42).is()` | `false` | `true` | diff --git a/examples/JsonHttpClient/JsonHttpClient.ino b/examples/JsonHttpClient/JsonHttpClient.ino index 8e945223..99bc2544 100644 --- a/examples/JsonHttpClient/JsonHttpClient.ino +++ b/examples/JsonHttpClient/JsonHttpClient.ino @@ -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 #include #include -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(); + client.println() || die("Failed to send request"); - 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!"); + 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; -} + echo("Skip HTTP headers"); + char endOfHeaders[] = "\r\n\r\n"; + client.find(endOfHeaders) || die("Invalid response"); -// 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 - - // 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; - } + echo("Extract values"); + echo(root["sensor"].as()); + echo(root["time"].as()); + echo(root["data"][0].as()); + echo(root["data"][1].as()); - // 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"); + echo("Disconnect"); client.stop(); } -// Pause for a 1 minute -void wait() { - Serial.println("Wait 60 seconds"); - delay(60000); +void loop() {} + +void echo(const char* message) { + Serial.println(message); } + +bool die(const char* message) { + Serial.println(message); + while (true); // loop forever + return false; +} \ No newline at end of file