Browser to Device LED Control using SimpleMQ

(Controlling Devices Over the Internet of Things)

In this tutorial, we show how to use the SMQ IoT Protocol for designing a web-based IoT device management user interface for controlling Light Emitting Diodes (LEDS) in one or multiple devices. The application will consist of a browser-based control user interface and device code implemented in C and designed for embedded devices. We also provide a simulated version that may run in a terminal window both on Windows and Linux.

This tutorial builds on what you learned in the two tutorials Designing a browser-based Chat Client using SMQ and Improving the browser-based Chat Client, which explain publish/subscribe and one-to-one direct messaging.

For a quick, visual understanding of the IoT LED example, check out our TL;DR intro below:

  • Paste the following into a Linux or Windows WSL shell, or use our online Linux Web Shell:
    git clone
    cd SMQ
  • When the LED-SMQ program starts, it connects to the online broker and should show up in the iframe below:

You can now control the simulated LEDs using the Linux shell and using the above UI.

The Client User Interface

This article focuses on the JavaScript-powered HTML application as shown in the above iframe. However, we provide the following additional client user interface design tutorials:


See the DZone article Java IoT Device Management using SMQ if you are a Java programmer.

ReactJS, Angular, and Vue.js?

The Web Based User Interface (UI) in this tutorial is powered by JavaScript and uses the JQuery JavaScript library for UI rendering. We also have a tutorial for modern frameworks such as AngularJS, ReactJS, and Vue.js, with a web based UI developed using Vue.js. See the tutorial How to use AngularJS, ReactJS, and Vue.js with any web server for details.

LED Control Design

The device will publish its given capability as a JSON object to the named topic "/m2m/led/device". All browsers are subscribed to this topic and will be alerted to any new device(s) that may join the network.

Publish to Device

Figure 1: new devices joining the network send a list of capabilities to connected browsers.

The JSON object sent to the "/m2m/led/device" topic includes the number of LEDs in the device, the LED colors, and an ID (number) for each LED. The browser will use the information provided to add a new tab per connected device and then dynamically create HTML based on the capabilities presented by the device in the JSON object.

New browsers joining the network will send a message to allow all devices to subscribe. The browser starts by publishing a message to the named topic "/m2m/led/display"; thus, all existing devices will receive the message as illustrated in the figure below.

Publish to Display (Browser)

Figure 2: new browsers joining the network send a "hello" message to the named topic "/m2m/led/display".

Ephemeral topic ID

We introduced Topic IDs, Sub Topic IDs, and Ephemeral Topic IDs in the Chat Client Tutorial. At this point, you may want to review either the chat client tutorial for an introduction to these features or read the SMQ documentation, which introduces these unique IoT features as used within SMQ.

JavaScript (Browser) Code

The device will respond to the browser publication by sending a message back to the "sender" of the message. The message's sender is known as the publisher's ephemeral topic ID (ptid). The ptid that was introduced in the chat client is an ephemeral ID that uniquely identifies a specific client connected to the broker. The message sent to the ephemeral ID is the same JSON data as sent to the "/m2m/led/device" topic (figure 1) and enables the browser to dynamically build a user interface for the connected device(s).

The following code snippet shows how the JavaScript code in the browser subscribes to the topic "/m2m/led/device" and to the topic name "self", which means that the browser subscribes to messages sent to the client's own ephemeral ID. Notice that the message callback function "devInfo" is the same for the two subscribe calls below. One is for receiving JSON messages sent to the topic "/m2m/led/device", and the other is for receiving messages received on the ephemeral topic ID.

smq.subscribe("/m2m/led/device", "devinfo", {"datatype":"json", "onmsg":devInfo});
smq.subscribe("self", "devinfo", {"datatype":"json", "onmsg":devInfo});

Example 1: Subscribing to topic "/m2m/led/device" and to the device's own ephemeral topic ID.

The "devInfo" callback function receives incoming messages as parsed JSON objects. The "datatype" parameter instructs the SMQ client stack to parse the incoming message as JSON. The "devInfo" callback function is called when a device publishes to the named topic "/m2m/led/device" or to the client's ephemeral topic ID ("self"). Notice that we are further refining the subscription by setting a secondary topic name[w1]. Both subscribe requests above include the secondary sub-topic name "devinfo". Secondary sub topic names, aka sub-topics, are optional in the SMQ protocol. We use them in this example for differentiating sub-messages sent on a particular topic.

The "devInfo" callback function, not shown here, dynamically builds the HTML user interface based on the device's capabilities as presented in the JSON object. See the source code for details on this function.

When a user clicks an LED for one of the devices connected, we must first be able to uniquely identify the device and then uniquely identify the LED in the device. We can do this by embedding the publisher's ephemeral topic ID (ptid) and LED ID in the dynamically generated HTML.


Example 2: creating an HTML id that uniquely identifies an LED in a device by combining ptid and LED ID.

A click event callback function is installed on the HTML element and this function gets called when a user clicks on the LED button's on/off switch.

function clickCallback() {
    var id = $(this).prop('id').match(/(\d+)-(\d+)/);
    var ptid = parseInt(id[1]);
    var ledId = parseInt(id[2]);
    var data = new Uint8Array(2);
    data[0] = ledId;
    data[1] = this.checked ? 1 : 0;

Example 3: extract ptid and LED ID from the HTML element on user click events.

Line 1: We use regular expressions to extract the ptid and LED ID from the HTML element's 'id'. The regular expression matches the format we used in example 2 where we created the HTML element's id.

Line 3 - 4: The ptid and LED ID extracted from the regular expression are string values. These must be converted to number values.

Line 5- 7: The LED state change is sent as a two-byte binary array to the device, where byte one is the LED ID, and byte two is "one" for LED on and "zero" for LED off.

Line 8: The two-byte binary packet is sent to the device's ephemeral topic ID. We get the ephemeral topic ID when the device sends its capability list as a JSON object. We can now use this number to send a message directly to the device. The following figure illustrates how a browser sets an LED in a specific device by publishing to the device's ephemeral topic ID.

Set LED by publishing to device's ephemeral ID

Figure 3: The device receives a set LED command from the browser, updates the LED, and publishes the LED status to all browsers.

The set LED command is published to the device's ephemeral topic ID on line 8 in example 3. When the device receives this command, the device sets the LED and sends a LED state change command to all connected browsers by publishing to the named topic "/m2m/led/device" and sub-topic "led". All browsers subscribe to this topic; thus, clicking an LED in one browser will automatically set the LED in all the other connected browsers.

function led(data, ptid) {
    var ledId = data[0]; 
    var checked = data[1];
    //Update user interface
//When a device publishes LED state change.
smq.subscribe("/m2m/led/device", "led", {"onmsg":led});

Example 4: subscribing to topic "/m2m/led/device" and sub-topic "led".

Example 4 illustrates how the browser handles the LED state change event received from the device.

The above provides an introduction to the LED browser-based management code. There is more code involved than explained above, such as creating the HTML for the LEDs, managing the tabs for each connected device, and so on. The JavaScript code embedded in the LED management HTML page is fully documented, and we recommend that you study this code for the details.

Device C Code

You can compile the C code for Windows or Linux and run it in simulation mode. However, running it on an embedded device offers a more thorough understanding. In addition to the C code tutorial below, we provide an easy-to-follow Lua tutorial designed to run on an ESP32 microcontroller as showcased in the video at the top of this tutorial.

The device C code is split into two sections:

  • Generic code that implements the LED logic and code that interfaces to the SMQ C client stack.
  • Device-specific code that must be connected to LEDs in a particular device. The C code includes a section that should only be enabled when running the device code in simulation mode on Windows or Linux and when you have no LEDs to control. The interface functions required for LED device control are defined in ledctrl.h.

The device-specific code designed to interface to the physical LED(s) is straightforward, so we will not go into how this code works in this tutorial. Please see the code for details.

A device should, at startup, call the function "mainTask", which is a function that will not return unless the SMQ stack gets a forced disconnect request from the broker or if an unrecoverable error occurs.

void mainTask(const char* uuid, int uuidLen, const char* devInfo);

The first two parameters are for an ID required by the SMQ protocol. This ID must be unique but should preferably not change when the device restarts. The unique ID is typically generated in a device from the 6-byte MAC address associated with the Ethernet interface. The devInfo is an optional string that is sent to the broker when the client initially connects. The string may be used for identification purposes.

Connecting to a broker and establishing a persistent SMQ connection is a two-step process in C code. The following code snippet from the example shows the connect sequence in the example code (error checking is removed).

SMQ_init(smq, SIMPLEMQ_URL, 0)
            uuid, uuidLen,
            0, 0, /* credentials */
            devInfo, strlen(devInfo));

Example 5: the two-step sequence for establishing a persistent SMQ connection.

Function SMQ_init sends the initial HTTP connect command to the broker URL. The macro SIMPLEMQ_URL is set to our online demo broker You can change this URL and set it to your own broker.

SMQ_connect establishes the persistent SMQ connection. We are not using credentials in our example code so these two parameters are set to NULL.

Topic ID versus named topics

In the JavaScript example, we installed callbacks for receiving messages on named topics. We also published directly to named topics. The SMQ stack for C code provides a more bare-bone API and does not allow us to install callbacks. All messages are received by calling function SMQ_getMessage. The following example illustrates how the C code waits for messages from the broker.

int len =  SMQ_getMessage(smq, &msg);
if(len < 0) /* We received a control message or an error code */
   /* manage control messages and error codes */
else if(len > 0)
   /* Manage received message for a topic we subscribe to or manage
    * messages sent to our ephemeral ID. smq->tid is the topic ID for
    * the received message.

Example 6: distinguishing between received control messages, error codes, and payload data.

The SMQ protocol translates all topic names to topic IDs. A topic ID is a unique ID generated by the server when we either subscribe to a topic or request access to publish to a message. The topic IDs are partly abstracted away in the JavaScript code and we can work with named topics. However, the C code can only work with topic IDs. See the documentation on how the topic names are translated to topic IDs for details. The following code snippet from the LED source code shows how we request this information from the broker.

SMQ_create(smq, "/m2m/led/device"); /*So we can publish to /m2m/led/device*/
SMQ_createsub(smq, "devinfo");
SMQ_createsub(smq, "led");
SMQ_subscribe(smq, "/m2m/led/display");

Example 7: requests broker to create one topic ID, two sub-topic IDs, and subscribe to a topic.

Control Messages

The broker sends four ACK messages for the above four calls. The ACK messages have a negative value, so they can easily be distinguished from standard published messages. The following code snippet shows how to distinguish the various control messages received:

len =  SMQ_getMessage(smq, &msg);
if(len < 0) /* We received a control message or an error code */
      case SMQ_CREATEACK:  /* ACK: "/m2m/led/device" */
      case SMQ_CREATESUBACK: /*We get two suback messages (devinfo and led)*/
      case SMQ_SUBACK: /* ACK: "/m2m/led/display" */

Example 8: shows how to distinguish the various control messages from the requests sent in example 7.

Receiving payload data (messages published to a topic)

We have received a message published to a topic we have subscribed to when the function SMQ_getMessage returns a value greater than zero. Note: you are also automatically subscribed to messages published to your own ephemeral topic ID. The return value from SMQ_getMessage is either the complete frame payload data or the amount of data the SMQ client can buffer. You set the buffer and size when calling SMQ_constructor. We will not go into how to receive messages in fragments in this example since the messages we receive are small and will not be fragmented.

len =  SMQ_getMessage(smq, &msg);
if(len > 0)
   if(smq->tid == displayTid) /* topic "/m2m/led/display" */
      // Send device info to the new display unit
   else if(smq->tid == smq->clientTid) /* sent to our ephemeral tid */
      // 1: Set LED with ID ledId to on or off.
      // 2: Publish to "/m2m/led/device", sub-topic "led"

Example 9: receiving a message published to a subscribed topic.

SMQ::tid is set to the topic ID by the SMQ client stack. We can check this number and compare it with the topic IDs we are subscribed to. SMQ::clientTid is set to our own ephemeral topic ID; thus, we can find out if a peer published to our own ephemeral topic ID by comparing SMQ::tid and SMQ::clientTid. The browser(s) sends a message to the device's ephemeral topic ID when the browser wants the device to change an LED state to on or off. The device code will then set the LED to on or off and publish a message to the topic "/m2m/led/device". All browsers are subscribed to this topic and will update the user interface accordingly. You can test this feature by opening two browser windows. Clicking the LED in one browser window automatically updates the LED in the other browser window.

And this completes our introduction to the M2M LED SMQ version. You can download the complete C code as a ZIP file. Download, unpack, and study the source code file m2m-led.c.

The server side code and the web application are included in the Mako Server Tutorials. The C code can be downloaded from the SMQ source page. See the online SMQ documentation for more information.

Running the C Code in Simulation Mode

The following shows how to run the code in simulation mode on Linux or Windows Subsystem for Linux.

sudo apt install gcc make git
git clone
git clone
cd SMQ
#Run the compiled example:

The following shows how to run the code in simulation mode on Linux or Windows Subsystem for Linux using the secure (TLS enabled) version.

sudo apt install gcc make git
git clone
git clone
cd SharkSSL/build
#Run the compiled example:

Ready for a Professional Touch?

Our seasoned experts are ready to tackle your most pressing networking, security, and device management challenges. And if you're fueled by the DIY spirit, our rich collection of tutorials awaits to guide you. With us, you get the best of both worlds. Your project, our dedication.


OPC-UA Client & Server

An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.

Edge Controller

Edge Controller

Use our user programmable Edge-Controller as a tool to accelerate development of the next generation industrial edge products and to facilitate rapid IoT and IIoT development.

On-Premises IoT

On-Premises IoT Platform

Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.

Embedded Web Server

Barracuda Embedded Web Server

The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.

WebSocket Server

Microcontroller Friendly

The tiny Minnow Server enables modern web server user interfaces to be used as the graphical front end for tiny microcontrollers. Make sure to check out the reference design and the Minnow Server design guide.

WebDAV Server

Network File System

Why use FTP when you can use your device as a secure network drive.

HTTP Client

Secure HTTP Client Library

PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.

WebSocket Client

Microcontroller Friendly

The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.

SMTP Client

Secure Embedded SMTP Library

Send alarms and other notifications from any microcontroller powered product.

Crypto Library

RayCrypto C Library

The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.

Embedded PKI Service

Automatic SSL Certificate Management for Devices

Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.


Modbus TCP client

The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.

Posted in SimpleMQ