Transmit data over wifi to an Arduino (continued) —
In Part 10, sensor data were transmitted from a YellowJacket Arduino over wifi using http. As pointed out, the http wrapper that is received by the client from the server is difficult to parse to extract the data that are contained in the http transmission. In simple examples, the http page is small and gets sent without breaking the data into multiple packets (at least it seems that is the case). Reports from others on the web have raised the concern that data might get scrambled in some cases if the http packets get fouled. Some better way is required to add some intelligence with the data so it can be parsed successfully. Data parsing is a whole subject in itself, so only simple methods that can be implemented in Arduino sketches for testing WiShield wifi will be utilized in the following examples.
One better way to handle transmitted data uses some form of data structure that includes metadata to identify what is in the data structure, such as, dictionaries, XML, or JSON. JSON was chosen as the desired structure to move data across wifi devices.
JSON
JSON is widely used and well documented (www.json.org) so only a brief explanation will be given here.
- “JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate.”
- “JSON is built on two structures:
- A collection of name/value pairs.
- An ordered list of values.
- Virtually all modern programming languages support them in one form or another.”
JSON Implementation
The YJ56 Wifi/Sensor Shield data Server must have a software sketch that generates JSON formatted data for transmission. The YJ57 Wifi client must have a software sketch that will receive and parse the JSON formatted data, and then further process those data (display, store to SD Card, send to data base, initiate some action i.e. turn off the water).
The first example will expand on the http examples used in Part 10. The YJ57 client will use the same “SimpleWiClientReadWiServer_V3_02” sketch code, but with “GETrequest getWebPage(server_ip, 80, myhost_ip, “/json”);” implemented.
The YJ56 server will use a sketch that wraps the data into a JSON structure using some simple formatting. The server software then wraps the JSON data in the http response and transmits the http response to the client (YJ57) that requested the data.
Two data elements, 1) temperature, and 2) photocell reading are sensed on the Sensor Shield. Those data are written as a formatted char string into a character array, json[], then that char array is placed inside custom tags, <json>…</json>, which simplifies parsing the json data from the http wrapper by the client. On the Arduino, tags within an http response are not automatically parsed by the client as they are on a web browser, so tags are just passed as characters as part of the incoming http response.
example data: char json[] = "{\"val1\":\"12.34\",\"val2\":\"56\"}";
/* * SimpleJsonServer_V3 * A simple sketch that uses WiServer to serve a web page * containing JSON formatted data * */ #include <WiServerIO.h> #define WIRELESS_MODE_INFRA 1 #define WIRELESS_MODE_ADHOC 2 // Wireless configuration parameters ---------------------------------------- unsigned char local_ip[] = {10, 0, 1, 56}; // IP address of WiShield unsigned char gateway_ip[] = {10, 0, 1, 1}; // router or gateway IP address unsigned char subnet_mask[] = {255, 255, 255, 0}; // subnet mask for the local network const char ssid[] PROGMEM = {"Network"}; // max 32 bytes const char* myhost = "WiServer"; char* myhost_ip = "10.0.1.56"; unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2 // WPA/WPA2 passphrase const char security_passphrase[] PROGMEM = {"Network_Passcode"}; // max 64 characters // WEP 128-bit keys // sample HEX keys const uint8_t wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3 }; // setup the wireless mode // infrastructure - connect to AP // adhoc - connect to another WiFi device unsigned char wireless_mode = WIRELESS_MODE_INFRA; unsigned char ssid_len; unsigned char security_passphrase_len; //--------------------------------------------------------------------------- /****************************** Data Logger ********************************** * * Assign the data sensors to the Arduino analog pins * */ //#define aref_voltage 3.3// we tie 3.3V to ARef and measure it with a multimeter! #define aref_voltage 5.0 // default internal 5V to ARef int photocellPin = 1; // the cell and 10K pulldown are connected to a1 int photocellReading; // the analog reading from the analog resistor divider int temperaturePin = 0; //the analog pin connected to the TMP36's Vout (sense) pin int temperatureReading; // the analog reading from the sensor char inCMD[23] = "/write_json_2data.php?"; // php file to process the json POSTrequest char vj1[10]; // sensor 1 data as char array char vj2[10]; // sensor 2 data as char array float tempF; // float sensor 1 data // int tF; // int sensor 1 data if desired /*************************** Sketch functions ************************************/ /*************************** mySensor ************************************/ // loop Function that assembles data to send to the server void mySensor() { // Read sensors data photocellReading = analogRead(photocellPin); temperatureReading = analogRead(temperaturePin); // converting that reading to voltage, which is based off the reference voltage float voltage = temperatureReading * aref_voltage / 1024; // calculate temperature float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset // //to degrees ((voltage - 500mV) times 100) //Serial.print(temperatureC); Serial.println(" degrees C"); // convert C to Fahrenheit tempF = (temperatureC * 9 / 5) + 32; Serial.println(F(">>> Read sensors ")); // Print the sensor values to the Serial Monitor Serial.print(tempF); Serial.println(F(" degrees F")); Serial.print(photocellReading); Serial.println(F(" Photocell")); // convert int to char uses sprintf // convert float to char uses dtostrf // note: <dtostrf(tempF, 6, 2, data);> will add a leading blank for the - sign // which fails to load the data into MySQL table. Use <dtostrf(tempF, 0, 2, data);> // which will left justify the data xyz.dd, and will load into MySQL dtostrf(tempF, 0, 1, vj1); // converts float to char[] array (data) //Serial.print(data1); Serial.println(F(" data1 char dtostrf degrees F")); // tF = (int)tempF; // if int value is desired rather than float // sprintf(v1, "%i", tF); // converts int to char[] array (data) //Serial.print(tF); Serial.println(F(" int degrees F")); sprintf(vj2, "%i", photocellReading); // converts int to char[] array (data) //Serial.print(v2); Serial.println(F(" data char int degrees Photocell")); } /*************************** sendMyPage function *********************************/ // This is our page serving function that generates web pages boolean sendMyPage(char* URL) { // Check if the requested URL matches "/" if (strcmp(URL, "/json") == 0) { // Use WiServer's print and println functions to write out the page content WiServer.println("<html>"); // for Arduino to Arduino over wifi, use <json> and </json> tags as delimiters for parsing // print <json>...</json> on one contiguous line WiServer.print("<json>"); // test example json data array //char json[] = "{\"val1\":\"12.34\",\"val2\":\"56\"}"; // example JSON //WiServer.print(json); // obtain the sensor values mySensor(); // place sensor data into JSON format WiServer.print("{\"val1\":\""); WiServer.print(vj1); WiServer.print("\",\"val2\":\""); WiServer.print(vj2); WiServer.print("\"}"); WiServer.println("</json>"); WiServer.println("</html>"); // URL was recognized return true; } // URL not found return false; } /*************************** setup function *********************************/ void setup() { // If you want to set the aref to something other than 5v //analogReference(EXTERNAL); // enable EXTERNAL if using 3.3 AREF, ie, SD Card Shield and UNO analogReference(DEFAULT); // DEFAULT for no external AREF, ie, SD Card Shield and YellowJacket // Enable Serial output Serial.begin(115200); // /* Serial.println(""); Serial.println(">> SimpleJsonServer_V3 sketch "); Serial.print(">> WiServer.server_task initialized on "); Serial.print(myhost); Serial.print(", ip: "); Serial.println(myhost_ip); // */ // Initialize WiServer and have it use the sendMyPage function to serve pages WiServer.init(sendMyPage); // Verbose=true >> ask WiServer to generate log messages to Serial Monitor WiServer.enableVerboseMode(true); Serial.println(""); Serial.println(F(">> Listening for connections...")); } /*************************** loop function *********************************/ void loop() { // Run WiServer WiServer.server_task(); delay(10); } /*************************** end loop function *********************************/
The YJ56 Wifi server running the SimpleJsonServer_V3 sketch displays the following on the Arduino Serial Monitor display:
>> SimpleJsonServer_V3 sketch >> WiServer.server_task initialized on WiServer, ip: 10.0.1.56 >> Listening for connections...
The YJ57 Wifi client running the SimpleWiClientReadWiServer_V3_02 sketch sends the “GETrequest getWebPage(server_ip, 80, myhost_ip, “/json”);” request over wifi to YJ56 which takes a reading of the sensor data, packages it as an http response, transmits the http response to YJ57, which then displays the following on the Arduino Serial Monitor display:
=== Initializing WiClient to display WiServer web page on Serial Monitor === === WiClient is running... === >>> Request response on 10 second intervals... Connected to 10.0.1.56 TX 65 bytes RX 0 bytes from 10.0.1.56 RX 78 bytes from 10.0.1.56 HTTP/1.0 200 OK <html> <json>{"val1":"72.1","val2":"66"}</json> </html> . Ended connection with 10.0.1.56 . Connected to 10.0.1.56 TX 65 bytes RX 0 bytes from 10.0.1.56 RX 78 bytes from 10.0.1.56 HTTP/1.0 200 OK <html> <json>{"val1":"72.1","val2":"65"}</json> </html> . Ended connection with 10.0.1.56 .
The json char array, formatted as name/value pairs, and delimited by <json>…</json> tags, have successfully been transmitted over wifi within the http response.
Next, the json char array will be parsed and processed in some usable fashion.
(Mar 9, 2016)
No comments:
Post a Comment