Modern Approach to Embedding a Web Server in a Device

In this article, we will look into how we can modernize embedded web-based device management using reactive programming techniques for the user interface and the complete solution, including changes propagated in real-time from the device to all connected browsers. A modern reactive web-based application is commonly assembled as a Single Page Application (SPA), and many tools facilitate reactive SPA development, including AngularJS, ReactJS, and Vue.js. We will move on to designing a reactive multiuser-based solution for controlling shared resources in the device. Our fully functional example can be downloaded and loaded in your browser and run without installing any software.

Note: we use a JavaScript toolkit called Vue.js in the following tutorial. However, the toolkit should not be your focus when reading the tutorial. The focus should be on the reactive nature of the solution as a whole, including the synchronized state of multiple views (multiple browser windows) -- in other words, think holistically when reading the tutorial.

Reactive programming is a programming paradigm oriented around data flows and the propagation of change. In a web-based device management system, change propagation may come from a user clicking a button but also from reactive events in the device. These events must be propagated to all connected browser user interfaces.

Old Style (Traditional Solution)

Let's start by looking at a traditional embedded web device management approach for turning a light bulb on or off using a web server embedded in a device, which controls the light bulb's on/off switch.

Embedded Web Server Controlling a Light Switch

Figure 1: Traditional web-based device management interface.

The above figure shows a traditional web design solution for controlling a light bulb. An HTML file is loaded from the embedded web server into the browser, and a web form similar to the following is embedded in the HTML page:

<form method="post">
   Light On/Off: <input name="lightbulb" type="checkbox">
   <input type="submit">
</form>

The user must first check or uncheck the checkbox and then press the submit button. The browser then sends this as a POST request to the server, where server side logic processes the request and turns the light bulb either on or off.

We can apply a quick fix to the user interface and make it more aesthetic and modern looking by simply applying cascading style sheet (CSS) to the checkbox. Most modern browsers support the latest CSS3 technology. By using CSS only (no images), we can quickly modernize the user interface and make it look like the UI shown in the following figure:

Embedded Web Server Controlling a Light Switch - Styled Version

Figure 2: Traditional web-based device management interface with modern CSS.

Note that we have, at this point, only applied modern CSS. The application works identically to the one shown in Figure 1. The user must still perform the two-step procedure for turning the light bulb on or off by clicking the light switch (checkbox) and the submit button.

We can simplify and further modernize the application and replace the submit button requirement by using JavaScript and AJAX. We can install a JavaScript callback function that triggers when the user clicks the checkbox. The JavaScript callback function receives the checkbox's on/off state when the user clicks the checkbox and uses AJAX to send this information to the server.

AJAX makes sending asynchronous events from a browser to the device easy and may seem like the ideal solution for our web-based on/off light bulb switch. However, AJAX provides only asynchronous events from browser to device, not the other way around. This immediately becomes problematic if a second user opens the same light bulb switch UI in another browser. The server receives an asynchronous on/off event from one browser but cannot notify the second browser, the two user interfaces become out of sync, and the one not updated will provide stale information to the user.

Reactive WebSockets for Multiuser Real-Time Device Management of Shared Resources

We can fix the limitation in AJAX technology by using WebSockets, a newer technology supported by all modern browsers. WebSockets provides a full-duplex asynchronous (reactive) communication channel over a single TCP connection.

The fact that WebSockets provides a bi-directional communication channel between the browser and server immediately opens up some exciting opportunities for web-based device management applications. Because the connection is persistent, the embedded web server can now initiate communication with the browser. The embedded web server can send alerts, updates, notifications, etc. This adds a whole new dimension to the types of web-based device management applications that can be constructed.

In our basic light switch application, we will use WebSockets to keep any browser user interfaces connected to the server synchronized. The following figure illustrates the sequence of events. When a user clicks the light switch in the browser, a "Set Event" is sent to the server, which in turn sets the light bulb state. The server finishes the request by sending an "Update Event" to all connected browsers.

Synchronized and Reactive Web User Interfaces

Figure 3: Two synchronized browser user interfaces managing a shared resource controlled by the server

The Set Event/Update Event behaves similarly to an AJAX call but with one major difference. The response to the request, the Update Event, is sent to the originator and all connected browsers. The AJAX protocol can easily be built using Websockets technology, and Websockets can be seen as a superset of AJAX. WebSockets enables us to respond to user inputs in real-time and reactively update all connected browser user interfaces simultaneously.

We can directly use the WebSocket API provided by the browser and the API provided by the server. However, a raw WebSocket connection is similar to a raw TCP connection. A raw WebSocket connection does not provide an easy-to-use high-level API for sending messages. What we need is a protocol that sits on top of WebSockets, and that provides an easy-to-use messaging API.

The "Update Event" message shown in Figure 3 requires the one-to-many design pattern and a publish/subscribe (pub/sub) protocol provides this feature. A pub/sub protocol makes sending messages to all connected browsers easy. Publish/subscribe protocols typically require a broker. Many embedded application servers, such as the Barracuda Application Server, include a broker as an integral part of the server solution. The following figure illustrates how a server-side custom light bulb app can communicate with all connected browsers via the broker.

Embedded Device and Broker

Figure 4: An embedded pub/sub broker serves as the browser to device communication manager

Example Program

A working example is worth a thousand words; however, how can one provide an easy-to-use light bulb device management demo without real hardware? The solution we came up with was to decouple the Light Bulb App from the device and implement the Light Bulb App as a web application. This slightly complicates the design since the solution must now be able to not only manage one light bulb but 0 to N light bulbs. In other words, the solution must be able to manage any number of browsers that have loaded the Light Bulb App.

In fact, our example program simulates a common industrial device management setup where a main controller is in charge of managing N microcontrollers. The main controller typically includes an embedded web server that enables an operator to manage all connected microcontrollers via the main controller. The following figure illustrates how such an industrial setup may function.

Embedded Device IoT Solution

Figure 5: A common industrial setup where a main controller manages N microcontrollers.

In our example program, we selected Vue.js for the Light Switch app and JQuery for the simulated Light Bulb App. We will not focus much on the simulated Light Bulb App since this application would typically be part of the server (Fig. 4) or microcontrollers (Fig. 5) in a real application.

The Vue.js Light Switch App

We designed the Light Switch App such that it can be downloaded and run in any browser without having to install any software. Simply drag and drop the app into any browser, and it will connect to a server/broker we have running online.

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src='https://simplemq.com/rtl/smq.js'></script>
.....
<script>
// Connect to online test broker
var smq = SMQ.Client("wss://simplemq.com/smq.lsp");
.....
</script>

The first code line above includes Vue.js from a hosted service, a so-called CDN repository. The second line above includes the client-side SMQ JavaScript stack from the online test server. SMQ is the pub/sub protocol we use in this example. SMQ is similar to other pub/sub protocols such as MQTT. However, SMQ also provides some features not found in typical pub/sub protocols, such as one-to-one messaging and the sender's address. These extended pub/sub features are used in this example when sending a "Set Event" to a specific light bulb and when discovering new Light Switch Apps and Light Bulb Apps. SMQ, touted as an IoT protocol, has been specifically designed to enable developers to design multiuser reactive device management applications easily.

Notice how we use the hard-coded secure WebSocket URL wss://simplemq.com/smq.lsp in the above example. This construction makes it possible to run this example without having to install any web server software. In a real application, the URL would normally be to the origin server -- i.e., to the server from where the web page was loaded.

The main Vue.js application is as declared as follows:

<div id="app">
  <switchcomp v-for="bulb in bulbs" v-bind:bulb="bulb"
     v-bind:key="bulb.etid">
  </switchcomp>
</div>

The above HTML looking code is managed by Vue.js. The <switchcomp> element is a custom Vue.js component declared in the application. The <switchcomp> element is expanded/emitted by Vue.js for each Light Bulb App that connects to the broker. Vue.js' components enable us to create HTML snippets that can be dynamically inserted and removed in a running Single Page Application.

The HTML template for the <switchcomp> element is as follows:

<div class="switch">
  <div>
    <input type="checkbox" v-on:change="lightswitch" v-model="checked" />
    <div data-unchecked="On" data-checked="Off"></div>
  </div>
</div>

Notice the checkbox in the above HTML template. The div's and the checkbox renders the HTML Light Switch, as shown in Figure 2. Thanks to modern CSS, the template renders as an element that resembles a real light switch.

The above two HTML snippets probably look like gobbledygook if you are an embedded engineer or a web developer new to reactive frameworks such as Vue.js. It is outside the scope of this article to explain how Vue.js works and how the Vue.js part of this example works. You can find many good written tutorials and video tutorials online.

If you are an embedded computer programmer working for a company and you find Vue.js difficult to understand, a recommendation for you is to focus on the server side and use a Vue.js developer for the client-side application.

When the Light Switch application has connected to the online broker, the app publishes the following empty message to the pub/sub topic "/switchui/hello":

smq.publish("", "/switchui/hello");

The simulated Light Bulb App subscribes to the same topic:

smq.subscribe("/switchui/hello", {
    onmsg:function(msg,ptid) {
        smq.pubjson({on:on}, ptid, "/switch/set");
    }
});

The 'onmsg' is a callback that gets called when the Light Bulb App receives a "hello" message from a Light Switch App. The callback responds by sending a one-to-one message with the light bulb's on/off state back to the sender of the message. One of the features of the SMQ protocol is to provide a unique address for each connected client. This is referred to as the ephemeral topic ID or etid for short. The acronym ptid means the publisher's etid and is simply the sender's ID. The smq.pubjson() call above sends the on/off state as a JSON message back to the sender -- i.e., back to the Light Switch App that just connected.

The Light Switch App receives the one-to-one message sent by the Light Bulb App as follows:

smq.subscribe("self", "/switch/set", {datatype:"json", onmsg:onSet});

Subscribing to 'self' means subscribing to messages sent directly to the application and not via a standard named topic; in other words, the application subscribes to messages sent to the application's etid.

We register the callback function onSet above in the subscribe call. This function gets called when a Light Bulb App sends its on/off state.

function onSet(msg, ptid) {
    var bulb = app.bulbs[ptid];
    if(bulb)
        bulb.lightSwitch.checked=msg.on;
    else
    {
        Vue.set(app.bulbs, ptid, {on:msg.on,etid:ptid});
        smq.observe(ptid, function() {
            Vue.delete(app.bulbs, ptid);
        });

    }
};

As we mentioned above, each SMQ client gets a unique ID referred to as etid. The onSet function receives the publisher's etid as the second argument. We use this etid as a key for looking up the Light Switch's Vue.js component corresponding to the etid. If it is found, we set the checked element on the checkbox. Vue.js reactive logic will then automatically update the user interface to the correct on/off state. We have a new Light Bulb if the Light Bulb's etid is not found, and If so, we use Vue.js to dynamically create a new light switch.

Notice the smq.observer() call above. This construction makes the Light Switch remove the visual Light Switch in the user interface should the Light Bulb App close i.e. -- if you close the Light Bulb Apps' browser window, the Light Switch is automatically removed from the UI.

In addition to sending a direct one-to-one message from a Light Bulb to a Light Switch when it first starts, it must also send a one-to-many message when its light on/off state changes. This makes sure all Light Switch Apps stay synchronized.

The Light Bulb publishes to the "/switch/set" topic:

smq.pubjson({on:on}, "/switch/set");

All Light Switch Apps subscribe to this one-to-many message:

smq.subscribe("/switch/set", {datatype:"json", onmsg:onSet});

Notice that we use the same onSet callback for the above-named topic name subscription as we do for subscribing to the etid (self) in the previous code snippet above.

Run or Download the Examples:

You may download the complete code or run the Light Switch and Light Bulb App directly by clicking the links below, but check out the following video first.

Video: How to use the Light Bulb App and Light Switch App.

For more information on SMQ, see the online SMQ documentation and, in particular, the documentation for the SMQ JavaScript client used in the above code snippets. SMQ can also be used as a general IoT protocol. For more information, check out the online IoT cluster example.

Improving the Vue.js Example:

The example presented in this article uses a Content Delivery Network (CDN), where a generic Vue.js library is stored. However, using a CDN is not recommended for more advanced applications or production mode.

The tutorial using ReactJS, Angular, and Vue.js with any server shows how to bundle a real Vue.js application.

Conclusion

In this tutorial, we created a simple widget that automatically synchronizes its state between multiple views. Creating a web application with real-time widgets is reasonably easy. However, to design a large Fully Fledged Single Page Application and to maintain such an application can be very costly and time-consuming.

Comments:
We welcome your thoughts and discussions on this article. While our site does not host a comment section, please feel free to comment on LinkedIn: Modern Approach to Designing Industrial UIs.

The web development landscape has evolved significantly over the past two decades. From simple static sites, we've transitioned to complex and sometimes bloated "Single Page Apps". With the constant emergence of new JavaScript frameworks and many dependencies, even developing small web pages has become a significant challenge. The so-called modern web development ecosystem is vast and intricate; thus, unless you plan on dedicating 100% of your development efforts to mastering these client-side frameworks, it's highly recommended to collaborate with an external expert developer. Engaging with an expert consultant can ensure that your projects are developed efficiently, leveraging the latest technologies and best practices in the ever-evolving world of web development.

Multiuser Reactive Design Pattern Use Cases and Examples

On-Premises IoT tutorial with ready-to-run microcontroller code:

See our hands-on On-Premises IoT tutorial with code you can download and run, where we guide you through creating an On-Premises IoT solution. By the end of this guide, you'll have a functional IoT server set up locally. In this tutorial, you will also learn how to use ChatGPT for creating the project's initial code.

IoT Enabled Thermostat With Native-UI and Web-UI:

The SMQ Weather Application showcases the synchronization between a web-based user interface and the user interface of a device. The application is comprised of three components: the server application, the device (thermostat), and the browser-based user interface.

Please refer to the demo documentation for instructions on how to download the Windows demo executable and for information on how to synchronize all displays. Note that creating both a native UI and a web UI increases the cost as two separate user interfaces must be developed. However, modern web interfaces can easily replicate and provide the same user experience as any onboard UI; thus, native UIs are unnecessary with modern device design.

On-Premises IoT:

Learn how to use the multiuser reactive design pattern for designing your own on-premises IoT platform.

On-Premises IoT for Wind Turbines

Controlling Hardware Using a Microcontroller:

The following video shows how a synchronized multi-view (multi-user) web user interface can control a servo (a shared resource) in real-time via SMQ and WebSockets. The video is part of our ESP32 microcontroller getting started guide.


Additional Embedded Web Server Tutorials:


Looking for Guidance?

Your time is valuable. Let our expert consulting services streamline your networking, security, and device management tasks. And for those moments of DIY inspiration, our tutorials offer unmatched guidance. Partner with Real Time Logic and witness the seamless blend of expertise and empowerment.



OPC-UA

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

Modbus TCP client

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

Posted in Whitepapers