Skip to main content

The Connected Campervan Project - Building A Local Data Server with The ROCK 5B And Node.js

Previously, we introduced the Connected Campervan Project alongside the latest and very capable ROCK single board computer from OKdo. We explored the idea of building a fully interconnected off-grid monitoring system as an extension to the existing Kickstart Kamper project.

We also discussed the need for both empirical and data-driven research in the discussion around sustainable alternatives, such as renewable power, and the potential of the ROCK 5B  (249-3159) , to collect, log and interpret this data that can be taken from a range of digital sources available around the van.

The technical aim of the project, therefore, is to configure the ROCK hardware as a dedicated central computer and powerful data server for our off-grid environment, in order to track key metrics like solar yield and air quality that can be collected, shared, and discussed with the community in the context of overall feasibility.

The visualisation of this data will be key in sharing any findings, and so in this article, we will initially focus on building the foundation of our data server using the highly functional Node.js runtime environment, and a simple yet dynamic web-based user-interface in HTML and JavaScript.

Parts List

Setup

In order to build the software for our prospective system, the ROCK 5B needs to act as a conduit between low-level data sources such as RS485 from the solar charge controller, and higher-level server-side functions such as HTTP requests and database queries from our user-interface. Luckily, the ROCK comes well equipped out of the box with a familiar set of GPIO pins and a dedicated Debian operating system that both meet our requirements perfectly.

ROCK

Our ROCK 5B setup with wireless module and antennas

The ROCK also comes equipped with a Gigabit Ethernet port for fast networking, which we will be using to connect to our LTE router later in the project. However, for development purposes we will be using the ROCK wireless module to connect to the local network over Wi-Fi, this module will also allow us access to the latest Bluetooth 5.2 standard, which will be ideal for communicating with any wireless devices and sensors in the future. The Wi-Fi settings in the ROCK 5B Debian distribution are still in their early stages, but connecting to the local network manually is not overly complicated if you follow the Radxa guide here.

Given the scope of the project, we will be making good use of the very capable Node.js open-source runtime environment to develop our data server. Node.js is built for server-side functionality and IoT applications that uses JavaScript to create a uniform and seamless flow between client and server code, which in a sense, creates a full-stack JavaScript development environment for us to use.

sudo apt install nodejs

Installs the Node.js runtime environment

Having already booted Debian from an SD card as instructed, we can download and install Node.js using the terminal. This will allow us to open and run our JavaScript code project within the context of the Node.js environment.

sudo apt install npm

Installs the Node Package Manager

sudo npm install -g express

Installs the Express library globally for all future Node projects

We will also be using the Express library to streamline the dataflow in our server-side code and make network functions a bit easier for us to use. This process sounds complicated but we can actually install new Node libraries easily using the terminal and the Node Package Manager (npm) commands.

Opening our JavaScript server code in Node.js

With this complete, we should be able to run our code projects within the node environment in much the same way we do with other scripting language shells, by navigating to the project file location and running it with the node command. With the setup complete we can now make a start at writing the software for our user-interface and data-server respectively.

Building the User-Interface (Client)

The user-interface has been designed to be accessible on any device connected to the local Wi-Fi/LTE router in the van. Using a web-based application will make real-time monitoring more flexible and convenient while creating the potential to expand into more remote IoT functions later.

The bare-bones foundation of our HTML user-interface screen

The bare-bones foundation of our HTML user-interface

To start, we will be building a simple HTML page that can request data over HTTP to our server that will be hosted by Node and our ROCK board. Using raw HTML/CSS, we can create a landing page that can display our data in an intuitive format, and use JavaScript to request periodic updates.

// Update HTML elements with new data
function UpdatePage(newdata)
{
document.getElementById("temperature_data").innerHTML = newdata.temperature_data_JSON;
document.getElementById("light_data").innerHTML = newdata.light_data_JSON;
}
// Setup page to request updates every 5s
var intervalId = setInterval(function() 
{
$.ajax({
type: "POST",
url: "/",
contentype: "plain/text",
data: "hello",
success: (fromServer) =>
{
 UpdatePage(JSON.parse(fromServer));
}
});
}, 5000);

Periodic page updates handled in JavaScript using jQuery

If we type in the hostname and port number of the server into our browser it will send a HTTP get a request that will return the HTML page, CSS file, and JavaScript files needed to create our dynamic web page. We are also using the jQuery library to make HTTP post requests every few seconds, this returns a data series in JSON format from the server that we can use to automatically update the values in the table. I have used temperature and light level as examples of sensor inputs that could be measured.

Building the Server

We will be using the Express library in Node.js to help build our basic server while allowing us to seriously streamline our code and dataflow. Our main objective here is to take the relevant HTML, CSS and JavaScript files that make up our web interface and serve them to the user upon connection.

app.listen(port, hostname, function() 
{
  console.log('server running');
});

Listen for HTTP events

To do this we need to setup a listener on the hostname/IP address and port number of our choice, while creating event handlers to respond to HTTP get requests accordingly. For this test we will be using localhost and port 3000 so when the user connects to this socket, the relevant event handler will send the HTML page followed by the CSS and JavaScript files as the browser discovers these dependencies.

// Request HTML when required by the client
app.get(['/', '/index.html'], function(req, res)
{
res.sendFile((__dirname + '/client/index.html'));
console.log('homepage sent');
});
// Request Javascript when required by the client
app.get('/clientcode.js', function(req, res)
{
res.sendFile((__dirname + '/client/clientcode.js'));
console.log('client JS code sent');
});
// Request jQuery library when required by the client
app.get('/jquery.min.js', function(req, res)
{
res.sendFile((__dirname + '/client/jquery-3.6.3.min.js'));
console.log('jQuery sent');
});
// Request style sheet when required by the client
app.get('/clientstyle.css', function(req, res)
{
res.sendFile((__dirname + '/client/clientstyle.css'));
console.log('client CSS code sent');
});

HTTP GET event handlers for client-side files

app.post(['/', '/index.html'], function(req, res)
{
console.log('page update requested');
let Rand_Temp = JSON.stringify(Math.floor((Math.random()*50)));
let Rand_Light = JSON.stringify(Math.floor((Math.random()*100)));
let helloData = {
temperature_data_JSON: Rand_Temp,
light_data_JSON: Rand_Light
};
res.send(JSON.stringify(helloData));
});

HTTP POST event handler for client-side data requests

Lastly, we need to configure an event handler for any HTTP post requests that will be received periodically from the client, which will in turn expect a reply containing fresh JSON formatted data to display to the user. In much the same way as the HTTP get request, we can setup a HTTP post event handler that parses some random placeholder data as a JavaScript key value pair into a JSON formatted string that is sent to the client and then displayed to the user.

Conveniently, as we are using JavaScript on both ends of our application, it makes it easier to send and receive this sort of formatted data and indeed whole JavaScript objects as required. It’s also amazing just how straightforward it is to setup our entire client-server stack with so little code.

Conclusion

Having finished our code, we have now successfully established the basic functionality of our central data server using Node.js and the ROCK 5B, as well as some basic web-based visualisations in the user-interface. Naturally, we are aiming to expand on this functionality in future articles to include real sensor data inputs that we can send to the user in real-time, as well as some databases functions for historical data logging. Lastly, we have shown the potential of Node.js as a powerful development environment for networking and IoT based applications and I am looking forward to working with it more in the future.

For more details on this project check out the latest annotated code available on the Kickstart Kamper GitHub.

Visit the Kickstart Kamper landing page on DesignSpark

Visit the Kickstart Kamper official website

A keen maker and electronic engineer with a passion for the environment, renewables, alternative transport and anything off-grid. Man with a van and founder of the Kickstart Kamper sustainable campervan project. Grassroots Education Sustainability Ambassador. BrightSpark 2017. BEng. KickstartKamper.co.uk