CEJson: https://ardjson.codeplex.com
This now includes the Arduino apps covered in this blog.

Previous:Ardjson-Part 3b: cURL CRUD Examples

Additional: Ardjson-4b- Arduino Networking


The ToDoItems Microsoft Azure Mobile Services sample app has been examined in detail in the previous blogs in this series. It is a simple Universal App that records things "To Do" in a table on the service. The app lists all currently todo tasks, not yet tagged as complete. The user can add new tasks. When an item is complete the item is checked and is no longer listed in the app. The UI actions in the app are:

  1. Refresh the list of active (complete=false) ToDo tasks.
  2. Add a new ToDo task
  3. Mark a ToDo task as complete (via a checkbox)

The Universal app runs on Desktop Windows 8.1, Windows Phone 8.1 and Windows RT. In Parts 3 of this blog, it was demonstrated as to how to action these functions via a command line, using cURL.exe.

In this blog we will action those same actions from an Arduino device.

In parts 1 and 2 of this blog series, the TodoItems app was extended into a telemetry app that can record values of sensors. A later blog in this series will cover using an Arduino device to to interact with the Telemetry table in the Mobil Service in the same way. The final blog in this series will then use sensor values from actual sensors connected to an Arduino device


JSon Arduino Networking Code

This code is three programs; one for each of the ToDo actions as list above. The structure of these programs is:

  • Declarations
  • send_request( ) Form http request string and submit it
  • wait_response( ) Wait until connected for response
  • read_response( ) Get the response and process it
  • end_request( )  Disconnect from TCPIP connection when response is read.
  • set_up( ) Setup Serial and Ethernet (First thing called by an Arduino app)
  • loop( )  Call first four functions in order (Main loop for Arduino app, Continuously called after set_up( )).

The send_request and read_response functions are specific to each of the three apps.
The other code is common to all three. This code common  is listed in two parts:

  • The Common Declarations
  • The Common Functions. (wait_response, end_request, set_up and loop)

Common Declarations

Placed at the top of source file

#include <Ethernet.h>
#include <SPI.h>

// Ethernet shield MAC address (sticker in the back)
// Note: Will use DHCP
byte mac = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Azure Mobile Service address
// You can find this in your Azure Mobile Service dashboard
const char *server = "<Insert service name>.azure-mobile.net";

// Azure Mobile Service table name
const char *table_name = "todoItem";

// Azure Mobile Service Application Key
// You can find this key in the 'Manage Keys' menu on the Azure Mobile Service dashboard
const char *ams_key = "<Insert App Key>";

//Used to store the send and response strings
char jsonBuffer[640];

//The tenth line of the response contains the Json string
#define RESPONSE_JSON_DATA_LINENNO 10

Common Functions

Placed at bottom of source code (below send_request and read_response  functions:

// Wait for response
void wait_response()
{
  while (!client.available()) {
    if (!client.connected()) {
      return;
    }
  }
}


// Close the connection
void end_request()
{
  client.stop();
}

// Arduino Setup
void setup()
{
  Serial.begin(9600);
  while (!Serial) {
    ; // Wait for serial port to connect.
  }

  Serial.println("Starting Ethernet");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("**** Ethernet failed ****");
    for (;;) ;
  }
  Serial.println("Ethernet started");

  // Give the Ethernet shield a second to initialize:
  delay(1000);

}

// Arduino Loop
void loop()
{
  send_request();
  wait_response();
  read_response();
  end_request();

  //Only run once
  while(1)
    ;
}

The send_request and read_response functions, specific to each app follows:


[1] Get the list of active ToDo tasks.

  • Uses HTTP GET with a filter.

send_request( ) ::

// Send an HTTP GET request to the Azure Mobile Service data API
void send_request()
{
  Serial.println("\nconnecting...");
  if (client.connect(server, 80)) {
    Serial.print("sending ");  

    // GET URI
    sprintf(jsonBuffer, "GET /tables/%s?$filter=(complete+eq+false) HTTP/1.1", table_name);
    Serial.println(jsonBuffer);
    client.println(jsonBuffer);

    // Host header
    sprintf(jsonBuffer, "Host: %s", server);
    client.println(jsonBuffer);

    // Azure Mobile Services application key
    sprintf(jsonBuffer, "X-ZUMO-APPLICATION: %s", ams_key);
    client.println(jsonBuffer);

    // JSON content type
    client.println("Content-Type: application/json");

    // POST body
    sprintf(jsonBuffer, "", "");

    // Content length
    client.print("Content-Length: ");
    client.println(strlen(jsonBuffer));

    // End of headers
    client.println();

    // Request body
    client.println(jsonBuffer);

  } 
  else {
    Serial.
      println("connection failed");
  }
}

read_response( ):

// Read the response and dump to serial
void read_response()
{

  int jsonStringLength;
  int jsonBufferCntr=0;
  int numline=RESPONSE_JSON_DATA_LINENNO;
  //Ignore the response except for the 10th line
  while (client.available()) {
    char c = client.read();

    if (c == '\n')
    {
      numline -=1;

    }
    else 
    {
      if (numline == 0 )
      {
	  //Capture the 10th line in the response
	  //To do: Could be more deterministic about this:
	  //       Expect certain content, checks and balances etc.
        jsonBuffer[jsonBufferCntr++] = c; 
        jsonBuffer[jsonBufferCntr] = '\0';  
      }
    }
  }
  Serial.println("Received:");
  Serial.println(jsonBuffer);

  Serial.println("");
}

Output:

image
See the Arduino project in CEJson JSonToDoGetIncomplete for an implementation of this.
  • See the Discussion with respect to some output options, including parsing the JSon string.

[2] POST a new  ToDo Task

  • Uses HTTP POST
  • Note: Task is embedded in code as NewToDoTask1. You may wish to change this for every run.

send_request:

// Send an HTTP POST request to the Azure Mobile Service data API
void send_request()
{
  Serial.println("\nconnecting...");

  if (client.connect(server, 80)) {

    Serial.print("sending ");
    Serial.println(value);

    // POST URI
    sprintf(buffer, "POST /tables/%s HTTP/1.1", table_name);
    client.println(buffer);

    // Host header
    sprintf(buffer, "Host: %s", server);
    client.println(buffer);

    // Azure Mobile Services application key
    sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
    client.println(buffer);

    // JSON content type
    client.println("Content-Type: application/json");

    // POST body
    sprintf(buffer, "{\"text\":\"NewToDoTask1\",\"complete\":false);

    // Content length
    client.print("Content-Length: ");
    client.println(strlen(buffer));

    // End of headers
    client.println();

    // Request body
    client.println(buffer);

  } else {
    Serial.println("connection failed");
  }
}

read_response:

// Read the response and dump to serial
void read_response()
{
  bool print = true;

  while (client.available()) {
    char c = client.read();
    // Print only until the first carriage return
    if (c == '\n')
      print = false;
    if (print)
      Serial.print(c);
  }
}

 

Output:

Starting Ethernet
ipconfig:
192.168.0.103
255.255.255.0
192.168.0.1
192.168.0.1
Ethernet started
Looping

connecting...
sending BookDentist
POST /tables/todoItem HTTP/1.1
Host: sportronicsdj.azure-mobile.net
X-ZUMO-APPLICATION: NtcMLPQtuAqWtvXOwrZVQtqHevNUnN27
Content-Type: application/json
Content-Length: 39

{"text":"BookDentist","complete":false}
HTTP/1.1 201 Created

See the Arduino project in CEJson JSonPostNewToDoItem for an implementation of this.


[3] Mark a ToDo task as complete

  • Uses HTTP PUT or PATCH
  • This requires a specific record’s id (GUID)

send_request:

HTTP PUT, PATCH and DELETE require a record id, which with toDoItem table is a GUID. Filters cannot be used for these actions.

This means that the following code must be modified to include a specific record’s GUID before it is run. 

Hint: Amore complex example would use an index and search for that record’s GUID amongst the JSon string return from [1] above, and use that.

#define GIUD=<insert>
const char *  guid  = GUID;

/*
** Send an HTTP PATCH request to the Azure Mobile Service data API
*/
void send_request()
{
  Serial.println("\nconnecting...");
  

  if (client.connect(server, 80)) {

    Serial.print("sending ");
    Serial.println(guid);

    // POST URI
    sprintf(buffer, "PATCH /tables/%s/%s HTTP/1.1", table_name,guid);
    client.println(buffer);
    Serial.println(buffer);

    // Host header
    sprintf(buffer, "Host: %s", server);
    client.println(buffer);
    Serial.println(buffer);

    // Azure Mobile Services application key
    sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
    client.println(buffer);
    Serial.println(buffer);

    // JSON content type
    client.println("Content-Type: application/json");
    Serial.println("Content-Type: application/json");

    // POST body
    sprintf(buffer, "{\"complete\":true}");

    // Content length
    client.print("Content-Length: ");
    client.println(strlen(buffer));
    Serial.print("Content-Length: ");
    Serial.println(strlen(buffer));

    // End of headers
    client.println();
    Serial.println();

    // Request body
    client.println(buffer);
    Serial.println(buffer);

  } else {
    Serial.println("connection failed");
  }
}

read_response:

// Read the response and dump to serial
void read_response()
{
  bool print = true;

  while (client.available()) {
    char c = client.read();
    // Print only until the first carriage return
    if (c == '\n')
      print = false;
    if (print)
      Serial.print(c);
  }
}

Output:

connecting...
sending 4742AE79-628A-4FF5-84A9-B0B468263936
PATCH /tables/todoItem/4742AE79-628A-4FF5-84A9-B0B468263936 HTTP/1.1
Host: sportronicsdj.azure-mobile.net
X-ZUMO-APPLICATION: NtcMLPQtuAqWtvXOwrZVQtqHevNUnN27
Content-Type: application/json
Content-Length: 17

{"complete":true}
HTTP/1.1 200 OK

See the Arduino project in CEJson JSonCompleteToDoItem for an implementation of this.


Discussion

The first program, that GETS the active tasks, extracts the JSon string from the HTTP Response. No attempt was made to interpret the string and so it looks like a blob! The next blog introduces a simple JSon parser.



Next: CEJSon-5: A Simple JSon Parser