Part II: WebSockets for Real-Time Web and IoT Applications – Controlling Your NetBurner with WebSockets Interface

carlos-muza-900pxOpt

In this article, we will make a WebSockets dashboard application that provides real-time monitoring AND control of a NetBurner Core Module from a web browser. Previously in Part 1, we discussed the benefits of using WebSockets and demonstrated how to make a WebSockets application to remotely monitor the state of DIP switches on a NetBurner Core Module Development Kit. Next, we will build on the same example to show how we can also control the NetBurner Dev Kit’s integrated LED array in real-time from a browser using WebSockets.

Try Our ARM® Embedded IoT Dev Kit

Netburner ARM Cortex M7 embedded Development Kit for IoT product development and industrial automation.

Or, learn more about NetBurner IoT.

If you missed “WebSockets for Real-Time Web and IoT Applications Part 1”, we reviewed the WebSocket technology, its advantages compared to HTTP and AJAX, and the basics for getting a functional monitoring-only example running on a NetBurner Core Module Dev Kit. We covered starting an HTTP server, upgrading an HTTP connection to a WebSocket connection, sending JSON objects through a WebSocket, and browser-side handling of WebSocket messages. Look at Part 1 if you need a refresher.

Just like Part 1, to get started, you’ll need to download an example from the NetBurner Github repository, create a new project in NBEclipse IDE, and then import the source files that you downloaded from the repository into the project. If necessary, the NBEclipse Getting Started Guide provides more detailed instructions on these steps and can be found here or in your NNDK install in /nburn/docs/Eclipse. Most importantly, you’ll need a NetBurner Core Module Development Kit (which comes with a MOD-DEV-70CR development breakout board and one of our NetBurner core modules).

1. Adding LED Toggle Switches to the Webpage

First we’ll start by adding the webpage front-end UI needed to toggle the LEDs on our MOD-DEV-70CR development breakout board (comes with all NetBurner Core Module Developers Kits or can be purchased separately and fitted to an existing NetBurner core module).

<div style="width: 300px; height: 55px;">
<input id="cbox1" class="cbox" disabled="disabled" type="checkbox" />
<label class="lbl diplabel" for="cbox1">DIP Switch 1: </label>
<ul class="tg-list ledlist">
<li class="tg-list-item">
<h4>LED 0:</h4>
<input id="ledcb0" class="tgl tgl-skewed" type="checkbox" />
<label class="tgl-btn ledlabel" for="ledcb0" data-tg-off="OFF" data-tg-on="ON"></label>
</li>
</ul>
</div>

The block of HTML code above adds a CSS toggle switch to control the first LED on the MOD-DEV-70CR. This new CSS switch used for LED control is placed on our webpage so that it’s neighboring the CSS switch used to monitor the first DIP switch. The CSS switch for LED control in this code snippet has an ID of “ledcb0.” This ID will be used as a handle to allow us to get the value of the CSS switch, which will then be sent to the NetBurner module for parsing.

2. Sending JSON object to the NetBurner

function SetLED(event) {

    var ledJsonText;

    switch(event.id){
      case "ledcb0":
      var led0 = document.getElementById("ledcb0").checked;
      console.log(event.id + " : " + led0);
      ledJsonText = '{ "' + event.id + '" : "' + led0 + '" }';
      break;
    }

    if ((ws!=null) && (ws.readyState==WebSocket.OPEN)) {
        ws.send(ledJsonText);
    }
}

Upon clicking the switch on the webpage, SetLED() is called to handle the construction of the JSON object that contains the LED information, and sends the JSON object to the NetBurner via a WebSocket.

3. Receiving WebSocket messages on the NetBurner

if (FD_ISSET(ws_fd, &read_fds)) {
  while (dataavail(ws_fd) && (index < INCOMING_BUF_SIZE)) {
    read(ws_fd, IncomingBuffer + index, 1);
    openCount += ConsumeSocket( IncomingBuffer[index], inString, strEscape );
    index++;
    if (openCount == 0) {
      break;
    }
  }
}
if (openCount == 0) {
  int ledNum;
  bool ledValue;
  IncomingBuffer[index] = '';
  // iprintf("rx: %srn", IncomingBuffer);
  OSTimeDly(4);
  ParseInputForLedMask(IncomingBuffer, ledNum, ledValue);
  WriteLeds(ledNum, ledValue);
  index = 0;
}

The above logic was added to InputTask() to receive the JSON object from the WebSocket and toggle the LEDs. The WebSocket is read from until a full JSON object is received. ConsumeSocket() is used to let us know when we have received a full JSON object by checking for an open bracket, ‘{‘, and a matching close bracket, ‘}’. After receiving a full JSON object, we call ParseInputForLedMask() to parse the JSON object for the LED number and it’s state.

4. Parsing JSON objects on the NetBurner

static void ParseInputForLedMask( char *buf, int &ledNum, bool &ledValue ){
    ParsedJsonDataSet JsonInObject(buf);
    const char * pJsonElementName;
    int tempLedValue = 0;

    /* Print the buffer received to serial  */
    // JsonInObject.PrintObject(true);
    /* navigate to the first element name */
    JsonInObject.GetFirst();
    JsonInObject.GetNextNameInCurrentObject();
    /* Get a pointer to the first element's name */
    pJsonElementName = JsonInObject.CurrentName();
    /* Scan the element name for the LED number. Store the number value */
    sscanf( pJsonElementName, "ledcb%d"", &ledNum );
    /* Get the boolean value of the JSON element */
    ledValue = JsonInObject.FindFullNamePermissiveBoolean(pJsonElementName);
}

The NetBurner ParsedJsonDataSet class is used to parse the JSON object for the LED number and the state of the switch from the webpage.

5. Toggling the LEDs

/*-------------------------------------------------------------------
 * On the MOD-DEV-70, the LEDs are on J2 connector pins:
 * 15, 16, 31, 23, 37, 19, 20, 24 (in that order)
 * -----------------------------------------------------------------*/
void WriteLeds( int ledNum, bool ledValue )
{
   static BOOL bLedGpioInit = FALSE;
   const BYTE PinNumber[8] = { 15, 16, 31, 23, 37, 19, 20, 24 };
   static BYTE ledMask = 0x00;       // Stores the state of all 8 LEDs
   BYTE BitMask = 0x01;

   /* If this is the first call to this function, initialize the LED pins */
   if ( ! bLedGpioInit )
   {
      for ( int i = 0; i < 8; i++ )
      {
         /* Initialize the LED pins to GPIO */
         J2[PinNumber[i]].function( PIN_GPIO );
      }
      bLedGpioInit = TRUE;
   }

   // Write the LED state to the LED mask where bit0 represents LED0 and bit7 represents LED7
   if (ledValue)
   {
       // LED on
       ledMask |= (0x01 << (ledNum));
   }
   else
   {
       // LED off
       ledMask &= ~(0x01 << (ledNum));
   }

   // Write to all LEDs
   for ( int i = 0; i < 8; i++ )
   {
      if ( (ledMask & BitMask) == 0 )
      {
         J2[PinNumber[i]] = 1;  // LEDs tied to 3.3V, so 1 = off
      }
      else
      {
         J2[PinNumber[i]] = 0;
      }
      BitMask <<= 1;
   }
}

After parsing the LED number and state, we write the value to the LEDs with WriteLEDs().

The animated images below show how all of this turns out.

Example of control panel
The Web Interface to our Application
LEDs working on Dev Board
The Results in Action

6. Wrapping up

In the end, you’ll find yourself with an application that can monitor and control your NetBurner with the benefits of reduced latency and packet size supported by WebSockets! We hope this tutorial gives you enough information to get started with monitoring and controlling your own systems and components using WebSockets and a NetBurner Core Module. If you get stuck or want to share your implementation, please comment below!

Ready to learn how to secure your WebSockets? Move on to our next tutorial which tells you how to start using WebSockets Secure (WSS)…

Helpful Links

Share this post

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply
Click to access the login or register cheese