A node.js server that receives IoT sensor data and broadcast it via web
Introduction
I constantly strive to easily access real-time, high-frequency data streams, or remotely deploy sensor data. Following data acquisition, the convenience of analyzing or visualizing this sensor data through algorithms is essential.
This is a basic project that allows the Sensor_driven_by_MCU submit the data on to the nodejs_driven_server and allows the user record the data via web page that receives data from the nodejs_driven_server
via WebSocket.
see the diagram below:
+-----------------------+
| Server by Node.js |
| | \
> | | \ WebSocket
Http/Https -/ | | \
-/ +-----------------------+ \
/ v
+--------------+ +-------------------------+
| | |Browser |
| MCU client | |+----------------------+ |
| | || Web for Sensor data | |
| +---------+ | || | |
| | Sensors | | || data: 123.45 ... | |
| +---------+ | |+----------------------+ |
+--------------+ +-------------------------+
About Node.js
node.js
is a server framework that allows js coder build a backend logic. It can be also used for developing the desktop app.
2.1 Code for Server
cmd: npm install express
Javascript code for app.js
:
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const port = 8080; //port
const clients = new Set(); // for storing the connected WebSocket client
wss.on('connection', (ws) => {
clients.add(ws);
console.log('Client connected');
ws.on('close', () => {
clients.delete(ws);
console.log('Client disconnected');
});
});
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.post('/esp-data', (req, res) => {
const data = req.body; // obtain the data sent from micro chip
console.log('Received data from IoT data acquisition unit:', data.sensorValue);
/* broadcast the data to all the connected clients */
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(data));
}
}
res.send('Data received successfully and broadcasted via webSocket.');
});
server.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
Run: node app.js
2.2 Code for IoT Sensor MCU client:
The C code with Arduino as SDK for esp32 chip is:
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#define USE_SERIAL Serial
/*
remember to configure your server IP and wifi passCode before download this firmwear!
*/
WiFiMulti wifiMulti;
float sensorValue = 123.45;
float bias = 1;
void setup() {
USE_SERIAL.begin(115200);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
wifiMulti.addAP("UR_WIFI_SSID", "UR_WIFI_PASSCODE");
}
void loop() {
if (sensorValue > 126){
bias = -1;
}
if (sensorValue < 120){
bias = 1;
}
// wait for WiFi connection
if((wifiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n");
// configure traged server and url
//http.begin("https://www.howsmyssl.com/a/check", ca); //HTTPS
http.begin("http://YOUR_SERVER_IP:8080/esp-data"); //HTTP
http.addHeader("Content-Type", "application/json");
// read sensor data
sensorValue = sensorValue + bias;
//You can use `arduinojson` lib to assemble the json string:
String data = "{\"sensorValue\":" + String(sensorValue) + "}";
// post data to server
USE_SERIAL.print("[HTTP] POST...\n");
int httpCode = http.POST(data);
if (httpCode > 0) {
Serial.printf("[HTTP] POST request code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
USE_SERIAL.println(payload);
}
}
else {
Serial.printf("[HTTP] POST request failed.\n");
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
/* // HTTP GET:
USE_SERIAL.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if(httpCode > 0) {
// HTTP header has been send and Server response header has been handled
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
USE_SERIAL.println(payload);
}
} else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
*/
http.end();
}
delay(2000);
}
2.3 Code for front-end Web page:
The ./public/index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sensor Data Display</title>
</head>
<body>
<h1>Sensor Data Display:</h1>
<div id="sensorDataDisplay"></div>
<script src="main.js"></script>
</body>
</html>
and The ./public/main.js
file:
const sensorDataDisplay = document.getElementById('sensorDataDisplay');
let paragraph; // Declare a global variable to store the <p> element
const socket = new WebSocket(`ws://${window.location.hostname}:8080`);
socket.addEventListener('message', (event) => {
const newData = JSON.parse(event.data);
const timestamp = new Date().toLocaleTimeString();
const sensorValue = newData.sensorValue;
// If the paragraph element is already created, update its content
if (paragraph) {
paragraph.textContent = `Timestamp: ${timestamp}, Sensor Value: ${sensorValue}`;
} else {
// If the paragraph element doesn't exist, create it and append it to sensorDataDisplay
paragraph = document.createElement('p');
paragraph.textContent = `Timestamp: ${timestamp}, Sensor Value: ${sensorValue}`;
sensorDataDisplay.appendChild(paragraph);
}
console.log(newData); // Optional: Log the newData to the console for debug
});
/**
* If it is in append mode, i.e., the server sends a piece of data through WebSocket,
* and a new line is appended for each data entry, you can use the following main.js code.
*
* This is suitable for scenarios where you want to start recording sensor data when
* the webpage is opened.
*/
/*
const sensorDataDisplay = document.getElementById('sensorDataDisplay');
const socket = new WebSocket(`ws://${window.location.hostname}:8080`);
socket.addEventListener('message', (event) => {
const newData = JSON.parse(event.data);
const timestamp = new Date().toLocaleTimeString();
const sensorValue = newData.sensorValue;
// Create a new paragraph element to display the data
const paragraph = document.createElement('p');
paragraph.textContent = `Timestamp: ${timestamp}, Sensor Value: ${sensorValue}`;
// Append the paragraph to the sensorDataDisplay div
sensorDataDisplay.appendChild(paragraph);
console.log(newData); // Optional: Log the newData to the console
});
*/
Note: Remember to firewall-allow the port
used by the web app.
Subsequent work based on this proj.
- use Echarts framework for data visualization
- Record the data in file or database
- more function for specific scenarios