Application Logic

Since we are done with the project setup, let’s move on to write the actual logic contained in the above files.

GPIO Setup

From the circuit diagram above, we need to control three pins, each for Red, Green and Blue LED lights. Using onoff package, we can achieve this easily.

(File: led-control.js)

As discussed in the earlier article, onoff package uses the BCM pin numbering system. As per the circuit diagram, we have assigned a corresponding pin number to each color of the LED light.

We have exported a toggle function that takes a boolean value for each color of light. Based on these values, either 0 or 1 is written to the corresponding GPIO which makes it output 3.3V or 0V .

Server Setup

The next thing we need is an HTTP and WebSocket server.

(File: server.js)

In the above server.js file, we have imported express and socket.io library. Since we want to control GPIO from this file, we have also imported toggle function from the led-control.js file.

First, we need to create an HTTP server which is nothing but an express application. The express() function returns such an application.

Then we need to set up a few routes to serve .html and other asset files. Using app.get( '/', handler) settings on line no. 13, anyone who accesses our web application with / URL path will get the index.html file situated inside web-app directory. We should also make sure to send correct headers.

The next thing we need to configure is to setup assets delivery. Since our index.html files needs main.js and style.css file from the web-app directory, we are using standard express.js setting to deliver assets.

The socket.io.js file is also needed in the web application to communicate with the very SocketServer we are building. This file is located inside node_modules/socket.io-client/dist directory. On the line no. 23, we are simply instructing express.js to look for the asset files inside this directory if not found inside the web-app directory.

Once our express application is configured properly, we need to create an HTTP server instance from this application. Using app.listen() call on the line no. 26, the HTTP server starts at the 9000 port of the Raspberry Pi.

The app.listen call returns the reference to the HTTP server it has started. This is the low-level implementation of the HTTP server on the Node.js. This is what our WebSocket server needs.

We create a WebSocket server using the HTTP server instance using socketIO(server) call on the line no. 29. Unlike an HTTP server, a connection to the WebSocket server is persistent. Hence, the communication between the client and the server happens through events.

The io variable represents the WebSocket server. When a client (web application) is connected to this server, a connection event is received by the server. This event contains data about the client connection like the client’s id as well as an API to communicate with the connected client only.

Once the connection is established between the server and the client, the server can emit and listen to various custom events to and from the client. Each event can contain the additional payload (data).

However, in the above example, we are just listening to the led-toggle event from the client. A client sends this event when a button in the web application is pressed. This event contains the payload which has information about the state (on or off) of the individual RGB buttons.

Based on the payload of led-toggle event, we can toggle the state of GPIO pins connected to the RGB LED lights. Since we have already written a clean API to handle that inside led-control.js file, we are simply calling the toggle function when the led-toggle event is received.

Web Application

A web application is typically just a website which provides some useful static information or a much rich user-interface to communicate with the server.

In our case, even our web application will only contain some buttons to click on, we need to communicate with the server to emit these button press events. Since we need to send these events in real-time, we are using WebSocket connection over a traditional HTTP connection.

First, we need to do is design a relatively good looking user interface.

(File: index.html)

In the above snippet, we have created the index.html file which provides a simple user interface with three buttons. I have used Roboto Condensed font from the Google Fonts server for better UI.

You should also take a look at the asset files import. Since we have configured the express server to deliver asset files from the /assets path, that’s the path we need to use in the HTML file to import assets.

The last thing remained is to code the actual client to server communication logic. This logic is written in JavaScript inside main.js file.

(File: main.js)

In the above JavaScript file, we have created references to the individual button elements in the DOM and we are maintaining the state of each (on or off) button, through line no. 1 to 9.

Since we have imported the socket.io.js file in the index.html , it provides a high-level API to communicate with the WebSocket server we have built using socket.io . It provides the io interface which is used to connect with a remote SocketServer created using socket.io .

In the above example, I have used the IP address of my Raspberry Pi device. Since we are trying to connect to a server, we also need to provide the port number of that server to make a successful socket connection.

Once the socket connection is created successfully, the connection contains the API to communicate with the socket server. As soon as the connection is made, it receives the connect event from the server. This is a safe area to initialize any connection dependent variables or send events to the server.

In our example, we are listening to the button click events and once a button is pressed, we are emitting the led-toggle event to the WebSocket server on the connection object.

The connection.emit() call takes two arguments. First is the name of the event to emit and second is the payload to send along with the event. The payload structure of the event should match the payload structure expected by the SocketServer (see server.js file).

Starting the Web Application Server and Socket Server

Now that everything is in place, it’s time to fire up the engine. The only thing we need to do is to run the server.js file with Node.js. We do that using the below command.

$ node server.js

Once you execute this command, it will start an HTTP server on port 9000 . It will also start a WebSocket server but this server also runs on the same port. We can open http://<rpi-host>:9000 URL in the browser to access the web application we just built.

(URL: http://192.168.1.5:9000)

Once you open this web application, it will get connected to the WebSocket server. You can add additional logs to main.js (inside connect and disconnect events listeners) to check if the socket connection to the server is made successfully or not.

However, if you see the logs printed by the server.js, you should see a log message displaying the id of the connected socket client.

Express server started!

SOCKET: A client connected XaOGSG9KlEDul37hAAAA

If you see this message in the terminal where node server.js command was executed, then the client-server communication is established. Now you can press on the Red, Green or Blue button in the web application and your Raspberry Pi should toggle the LED lights just fine.