Intel Edison Or Arduino Control Using Windows Azure Mobile Services

Introduction

 
This article will guide you through the process of hooking up your Edison with Windows Azure, and how to do some cool stuff, such as controlling it. This example will just switch on and off an LED connected to any of the digital pins on the Edison board paired up with the Arduino breakout board. Let's see how it really works. An Azure mobile service will act as a bridge between the Edison and the controller (a Windows phone app is used here). Edison will read the value of an attribute from the table of the mobile service. A Windows phone app will update the value in the table, and thus we will make changes in the Edison code depending on the value.
 
Prerequisites
 
It is assumed that the reader has basic knowledge of Windows phone app development and can hook up the app with an Azure mobile service. If you are unfamiliar with creating a back end for your app, then go through this link.
 
Things Required (Hardware)
  1. Intel Edison with the Arduino breakout board
  2. A LED
Required Software
  1. Visual Studio
  2. Arduino IDE 
Services required
 
1: Azure mobile service
 
Firstly, let's create an Azure mobile service. There are lots of articles on creating an Azure mobile service. Follow this link and create a mobile service that will contain a single table and let's name it as controltable. The table will contain a column named "status" and another named "name". The value of the status column will either be 1 or 0, while the value for the name will be set to Edison/Arduino.
 
 
Now we will develop a Windows phone app that will add/modify the value of the attribute. The picture below shows us the screenshot of the Azure SQL table. Please note that the value of the attribute for “device” doesn’t matter. You can even exclude this attribute if you want to.
 
The next section will deal with the development of the Windows phone app.
 
Windows Phone App
 
Our app will consist of only two buttons: An on the button and an off button. The screenshot of the app is shown below. 
 
 
You can ignore the logout button, Actually, I was trying to add some features. Now, what will these buttons? This will update the value of the “status” attribute. When we press on the button, the value of “status” will be 1, else it will be 0.
 
There is a bit of a problem though. What to update if nothing is created? For that, we will deploy the app two times. The first time, we will create the table and assign some default values. The next time we will just update the previously updated values.
 
Now, our app is ready. Test the app and check whether the value of “status” is getting updated or not. Once it works, then there you go. The app is ready. The next part will concentrate on the Edison code.
 
Edison Code
 
Let’s get into Edison. Before kick-starting your code for your Edison, follow the initial steps mentioned here for configuring your Edison. After connecting your Edison, note your comport number. Then open up your Arduino IDE and select Intel Edison from the board. If you don’t find the Intel Edison option, then you need to download the necessary files from the "Boards Manager" option.
 
 
Once you open up the Arduino IDE, two functions will be mentioned from before: Void setup() and void loop(). The Edison has a built-in Wi-Fi. We will use the Wi-Fi to connect it to the Internet. So our first action is to include a library for Wi-Fi. Go to Sketch, include a library, then Wi-Fi. After that, let’s add up this code to connect it to Wi-Fi.
  1. #include <ArduinoJson.h>    
  2. #include <SPI.h>    
  3. #include <WiFi.h>    
  4.     
  5. char ssid[] = "avirup171"//  your network SSID (name)     
  6. char pass[] = "avirupbasu";    // your net ork password (use for WPA, or use as key for WEP)    
  7. int keyIndex = 0;            // your network key Index number (needed only for WEP)    
  8.     
  9. void setup()    
  10. {    
  11.   pinMode(13,OUTPUT);    
  12.   digitalWrite(13,HIGH);    
  13.   Serial.begin(115200);    
  14.   while (!Serial) {    
  15.     ; // wait for serial port to connect. Needed for Leonardo only    
  16.   }    
  17.       
  18.   // check for the presence of the shield:    
  19.   if (WiFi.status() == WL_NO_SHIELD) {    
  20.     Serial.println("WiFi shield not present");     
  21.     // don't continue:    
  22.     while(true);    
  23.   }     
  24.     
  25.   String fv = WiFi.firmwareVersion();    
  26.   if( fv != "1.1.0" )    
  27.     Serial.println("Please upgrade the firmware");    
  28.       
  29.   // attempt to connect to Wifi network:    
  30.   while (status != WL_CONNECTED) {     
  31.     Serial.print("Attempting to connect to SSID: ");    
  32.     Serial.println(ssid);    
  33.     // Connect to WPA/WPA2 network. Change this line if using open or WEP network:        
  34.     status = WiFi.begin(ssid, pass);    
  35.       
  36.   }    
  37. }    
The above code is responsible for connecting the Edison to the internet by Wi-Fi. Also, we have set PIN 13 to output mode and the current status is off. We will use the serial monitor of the IDE to monitor the process. Now, let's go to void loop(). Retrieving data from Azure is done by HTTP get method.
  1. void loop()    
  2.   {  
  3.     send_request();    
  4.     wait_response();    
  5.     read_response();    
  6.     end_request();    
  7.     delay(100);    
  8.   }   
These functions will retrieve the data from the Azure table. But before deep diving into the methods, we need to add some global variables to link our Edison to Azure service. Add these global variables:
  1. const char* server= "genesis-iot-control.azure-mobile.net";  //service URL    
  2. const char* table_name= "cloudcontroller"//Table name    
  3. const char* ams_key="Your application key";    
  4. char buffer[150]; 
The application key can be found in the manage keys button at your Azure portal. Now, we will write the code for the methods in void loop().
  1. void send_request()    
  2. {    
  3.   Serial.println("\nconnecting...");    
  4.     
  5.   if (client.connect(server, 80)) {    
  6.     
  7.     
  8.     // POST URI    
  9.     sprintf(buffer, "GET /tables/%s HTTP/1.1", table_name);    
  10.     client.println(buffer);    
  11.     
  12.     // Host header    
  13.     sprintf(buffer, "Host: %s", server);    
  14.     client.println(buffer);    
  15.     
  16.     // Azure Mobile Services application key    
  17.     sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);    
  18.     client.println(buffer);    
  19.     
  20.     // JSON content type    
  21.     client.println("Content-Type: application/json");    
  22.     
  23.     client.print("Content-Length: ");    
  24.     client.println(strlen(buffer));    
  25.     
  26.     // End of headers    
  27.     client.println();    
  28.     
  29.     // Request body    
  30.     client.println(buffer);    
  31.         
  32.   } else {    
  33.     Serial.println("connection failed");    
  34.   }    
  35. }   
We performed an HTTP request and called GET where we have indicated the name of the table previously, the name of the Server and code key; this to allow the correct retrieval of the data. Then we specified in what format the data needs to be retrieved and specified it as JSON. Let's write the code for wait_response().
  1. void wait_response()    
  2. {    
  3.   while (!client.available())     
  4.   {    
  5.     if (!client.connected())     
  6.     {    
  7.       return;    
  8.     }    
  9.   }    
  10. }   
Then we need to read the data retrieved. Since it's in JSON format, we need to parse the JSON string to get our desired value. Below is the example of a sample string.
{"id":"2492D996-C471-48F0-B3C9-F33E3B37477F","status":"0","name":"arduino"}
 
A very efficient library known as the ArduinoJson exist. This will do most of the parsing. But the retrieved JSON string is enclosed within '[' and ']'. These must be removed for the library to work. So, firstly you need to include the library in your code and add the following global variables and add:
  1. #include <ArduinoJson.h>      
  2.      
  3. #define RESPONSE_JSON_DATA_LINENNO 10      
  4.       
  5. int charIndex=0;      
  6. StaticJsonBuffer<200> jsonbuffer;      
Then write the following code in your read_response() method:
  1. void read_response()    
  2. {    
  3.   boolean bodyStarted;    
  4.   int jsonStringLength;    
  5.   int jsonBufferCntr=0;    
  6.   int numline=RESPONSE_JSON_DATA_LINENNO;    
  7.   //Ignore the response except for the 10th line    
  8.   while (client.available())     
  9.   {    
  10.     //Serial.println("Reading:");    
  11.     char c = client.read();      
  12.     if (c == '\n')    
  13.     {    
  14.       numline -=1;    
  15.     }    
  16.     else     
  17.     {    
  18.       if (numline == 0 && (c!='[')&& (c!=']') )    
  19.       {    
  20.         buffer[jsonBufferCntr++] = c;     
  21.         buffer[jsonBufferCntr] = '\0';     
  22.       }    
  23.     }    
  24.   }    
  25.   Serial.println("Received:");    
  26.   Serial.println(buffer);    
  27.   Serial.println("");    
  28.   parse();    
  29. }   
The above code will read the response and the parse method is responsible for decoding the string. The parse() method is shown below. In the parse() method itself, we will change the status of the PIN13.
  1. void parse()    
  2. {    
  3.   StaticJsonBuffer<150> jsonbuffer;    
  4.   JsonObject& root = jsonbuffer.parseObject(buffer);    
  5.   if(!root.success())    
  6.   {    
  7.     Serial.println("PARSING FAILED!!!");    
  8.     return;    
  9.   }    
  10.   int f= root["status"];    
  11.   Serial.println("Decoded: ");    
  12.   Serial.println(f);    
  13.   if(f==0)    
  14.     digitalWrite(13,LOW);    
  15.   else    
  16.     digitalWrite(13,HIGH);    
  17. }  
Here, in the above code, f stores the value of the attribute of status. Then, we check the value of f and ultimately set the PIN either to HIGH or LOW.
 
For a detailed documentation on ArduinoJson library visit this link. However, there is a bit of a problem with this library. It will be discussed later on. Now, we will write the remaining method's code. 
 
Now, you will see that when you compile the code, you will most likely encounter some errors. These errors needs to be removed. Before moving further have a look over this issue. The file WString.h misses some lines of code. The difference can be seen here. You need to update the file located here.
 
C:\Users\Username\AppData\Roaming\Arduino15\packages\Intel\hardware\i686\1.6.2+1.0\cores\arduino\WString.h
 
After updating your errors will be resolved. After you compile the code, burn it into your Edison and then you are done. When the code is burnt in your Edison, take a LED, and attach the longer leg of the LED to PIN13 and the shorter leg to Gnd. An optional 233-ohm resistor can be added with the longer leg. Thus, our Windows Phone controlled Edison via Windows Azure is ready. The screenshot of the serial window, while the Edison is in action, is shown below.
 
The first stage is when the Edison is attempting to connect to the Wi-Fi network.
 
 
The next stage is when the Edison is trying to connect to the Azure mobile service. After connecting, it obtains the JSON data which is then decoded by the JSON library and then we obtain the decoded result. The decoded result is responsible for the status of the PIN13 on the Edison.
 
 

Conclusion

 
Thus we have learned in this article how to control your Edison using Azure mobile services. Mobile service acts as a bridge. The Windows phone app alters data in Azure tables and ultimately the Edison is controlled. The article didn't cover the Windows phone development but a look at the links will provide you the info required. The entire Edison code is uploaded as a text file. The YouTube link for the video is here. If any problem regarding Wstring is encountered, then please leave a comment about the error.
 
Note: The pink lines in the article appears as it was copied from another article written by me at Intel Software for IoT. The link is here. Please ignore that.