Wednesday, March 9, 2016

YellowJacket Arduino with WiShield Wifi (Part 11)

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