This tutorial creates two independent files that make up the complete app. One is the backend .js file that runs in the node environment, acts as a webserver to serve the web app page then as a websocket server to communicate with the frontend app running in the browser.

All of the hardware control is performed by the backend NodeJS process, but it is directed by the messages from the front end web app.

The second file is the web app index.html file that runs in a browser.



We need to load the à la mods "comm" library first before we begin working on the app. To get the à la mods "comm" library and install it run the following commands from the home directory. This will retrieve the compressed library file, extract all the files into its directory structure and then using "npm" install all the NodeJS dependency modules.


> wget http://www.alamods.com/software/alamods.tgz > tar -xzvf alamods.tgz > cd ./alamods/comm > npm install

Another method of getting the à la mods "comm" library is via the "software" section within the resources page of the website.

One more general thing to do before we get into the actual application. We need to setup the file structure for NodeJS development. When running "npm init" you can use the defaults to most of the questions.


> cd ~ > mkdir isoiom17427 > cd ./isoiom17427 > npm init

We need to add a couple of modules that are not part of the native NodeJS set. Within the same directory run the following commands:


> npm install express --save > npm install socket.io --save

Once that is complete we can develop an app that runs on the Raspberry Pi to control the I/O and LED of the ISOIOM17427 module. If you're developing this directly on the Raspberry Pi you can use "nano" or your favorite editor. if you're using a PC you can use any web development IDE on a PC. We use JetBrain's WebStorm and Microsoft's Visual Studio Code, but anything will work that allows you to create and load the files onto the Raspberry Pi.


> sudo nano isoiom17427-webapp-registers.js

Add the following code:


let app = require("express")(); let http = require("http").Server(app); let io = require("socket.io")(http); let Comm = require("../alamods/comm/alamods-comm.js"); // -------------------------------------------------------------------- // --- HARDWARE SETUP // // The following section initializes all the modules that are used // to communicate to the à la mods module ISOIOM17427 // -------------------------------------------------------------------- // instantiate the Comm object let comm = new Comm('M'); // state machine variable to toggle the LED let ledState = "on"; // setup the à la mods stacking address // be sure the solder jumpers on the module are all removed if // you're using address 0 as setup here. const MODULE_ADDR = 0; // this is the port the web app page will be served from - the // express http server will listen on this port const WEB_PORT = 3000; // this gets the model number of the module // internal register 0x80 contains the model number - this is // two byte number (0 - 65535) that corresponds to the last // 5 digits of the general module name (i.e. ISOIOM17427 // model number would be 17427); let model = comm.moduleRegRead(MODULE_ADDR, 0x80); console.log(model); // turn the LED on solid to magenta // internal address 0x90 is the register that controls the // status LED on most à la mods smart modules. // bit 15 - determines register control // - 0 = default mode where module controls LED automatically // - 1 = register (0x90) control of LED // bit 2 = Blue LED // bit 1 = Green LED // bit 0 = Red LED comm.moduleRegWrite(MODULE_ADDR, 0x90, 0x8005); // -------------------------------------------------------------------- // --- WEB APP CLIENT // // The following section handles the interaction with the front-end // web app client // // Web sockets are used via socket.io to communicate bewteen the front- // end client and the backend app // -------------------------------------------------------------------- // respond to "/" requests with the index file - the web app is served // from here app.get('/', function(request, response) { response.sendFile(__dirname + '/index.html'); }); // respond to file requests app.get(/^(.+)$/, function(request, response) { response.sendFile(__dirname + request.params[0]); }); // setup the websocket server io.on('connection', function(socket) { // socket error handling - simply write a console message for now socket.on('error', function(error) { console.log(error.message); }); socket.on('disconnect', function() { }); socket.on('connect_failed', function(error) { console.log(error.message); }); // RX MESSAGE HANDLING // // the following section handles all incoming messages from the // front-end client on the specified channel "comm-channel" socket.on('comm-channel', function(data) { try { // parse the incoming byte stream into a JSON object let msg = JSON.parse(data); // process the received message according to the message type switch(msg.type) { // turn on the LED and relays case "on": // turn the LED on to magenta comm.moduleRegWrite(MODULE_ADDR, 0x90, 0x8005); // energize the relays (all) // register 0x10 is the relay control register comm.moduleRegWrite(MODULE_ADDR, 0x10, 0x00ff); break; // turn off the LED and relays case "off": // turn the LED off comm.moduleRegWrite(MODULE_ADDR, 0x90, 0x8000); // release the relays // register 0x10 is the relay control register comm.moduleRegWrite(MODULE_ADDR, 0x10, 0x0000); break; default: break; } } catch (ex) { console.log(ex.message); } }); }); // // START EXPRESS WEB SERVER // http.listen(WEB_PORT, function() { console.log("httpd listening on port 3000..."); });

When the app file is completed save it and run the following command:


> sudo node isoiom17427-webapp-registers.js

The output should look like:

> 17427

> httpd listening on port 3000...

The output on the terminal should be 17427, the LED should go to magenta and a line should appear stating the http web server is listening on port 3000. Now the backend app is ready to serve the web app page and accept websocket connections.

Next we'll need to create the web app front end index.html file. This file should be located in the same directory as the backend isoiom17427-webapp-registers.js file.


> sudo nano index.html

<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>à la mods</title> <style type="text/css"> html { user-select: none; } .button { width: 100px; height: 40px; line-height: 40px; margin: auto; color: white; background-color: #2ba3ce; box-shadow: 0 0 5px 2px rgba(100,100,100,0.5); cursor: pointer; margin-top: 20px; text-align: center; border-radius: 4px; } </style> </head> <body> <div id="onButton" class="button" onclick="buttonOn()" >ON</div> <div id="offButton" class="button" onclick="buttonOff()" >OFF</div> <script src="/socket.io/socket.io.js"></script> <script> // setup the websocket connection let webSocket = io.connect(location.host); // button "on" event handler function buttonOn() { // send the message to turn on system over the websocket webSocket.emit('comm-channel', JSON.stringify({ type: 'on' })); } // button "off" event handler function buttonOff() { // send the message to turn off system over the websocket webSocket.emit('comm-channel', JSON.stringify({ type: 'off' })); } </script> </body> </html>

To run the app make sure the backend app is running and listening for web connections.

In a web browser on the same machine as the backend app type in following URL:


localhost:3000

Or on another machine on the same network as the Raspberry Pi type in following URL:


<IP Address of Raspberry Pi>:3000

At this point you should see a web page with two buttons. One is "ON" and the other is "OFF". If all is working as planned when you click on the "ON" button the LED on the ISOIOM17427 module will turn magenta and all the relays will be energized (their associated LEDs should turn on also).

What is happening here with all of this? ALOT!

The backend has a web server listening on the port specified (3000). When the web app page is requested by going to "localhost:3000" the web server looks for the "index.html" file and sends it back to the browser. So far pretty standard web stuff. As the browser begins to parse the "index.html" file and setup the DOM alot more happens.

Once the browser hits the "script" tags the fun begins. The first one tells the browser to go out and request "socket.io.js" which is a library that makes handling asynchronous bi-directional messaging between the frontend web app page and the backend very straightforward. It has tremendous capability. Check it out.

After "socket.io.js" is loaded the browser starts to setup the next script which first tells the browser to open a websocket connection back to host where the page came from. Once the connection is opened the browser installs two event handlers on the buttons. Now the web app is completely setup and ready to go.

When one of the buttons is clicked the appropriate event handler fires sending a message over the open websocket back to the backend. The message is a serialized JSON object that is created by JSON.stringify({ type: 'on' })). Once it reaches the backend app it is deserialized by JSON.parse(data) and, therefore turned back into a JSON object. Which is very easy for the backend to handle.

The backend processes the message according to the "type" string in the message (i.e. 'on'). This occurs in the switch statement of the WEB APP CLIENT section. Inside each "case" of the switch statement is communication to the ISOIOM17427 module to perform the appropriate action according to the message type received from the front end web app.

Although we're showing uni-directional flow more could be added so the backend could push status updates asynchronously to the web app front end.

© à la mods. All rights reserved