
Modern Approach to Embedding a Web Server
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 to 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.

Figure 5: A common industrial setup where a main controller is managing 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.
Why Vue.js?
There is no shortage of web frameworks. The main reason we believe Vue.js is a good choice for device management is its small size. Many of the other frameworks come with major baggage and complicates the embedded device lifecycle management. There are additional benefits in using Vue.js besides its size. The Vue.js comparison page explains this in detail.
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.
1 2 3 4 5 6 7 | <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script src='https://simplemq.com/rtl/smq.js'></script> ..... <script> var smq = SMQ.Client("wss://simplemq.com/smq.lsp"); // Connect to online test broker ..... </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 easily design multiuser reactive device management applications.
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:
1 2 3 4 |
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:
1 2 3 4 5 6 |
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 if you are a web developer that is 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”:
1 | smq.publish("", "/switchui/hello"); |
The simulated Light Bulb App subscribes to the same topic:
1 2 3 4 5 | 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 ID of the sender. 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:
1 | 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 it’s on/off state.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 the Light Switch first starts, the Light Bulb must also send a one-to-many message when it’s light on/off state changes. This makes sure all Light Switch Apps stay synchronized.
The Light Bulb publishes to the “/switch/set
” topic:
1 | smq.pubjson({on:on}, "/switch/set"); |
All Light Switch Apps subscribe to this one-to-many message:
1 | 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.
About Real Time Logic
Real Time Logic is a world class IoT security and web-enablement specialist. Their solutions and Ecosystem Partners drive modern real-time embedded applications to ensure the smooth deployment and safe operation of next generation products. More details…
Find out more…
For more information on implementing bi-directional embedded control systems and user interfaces with WebSockets please complete the form below.