K O logo
IoT

IoT — Reading and sending sensor data

Author

Kalle

Date Published

 This AI-generated image depicts a Raspberry Pi project setup with sensors, LEDs, and wires connected to a breadboard. A laptop displays code, and holographic icons represent various sensor readings like temperature and humidity.

One of the most common use cases of IoT is reading and collecting sensor data. Here I will show an example using the DHT11 sensor which reads the temperature and humidity values in its environment.

A simple setup would look like this, the sensor is connected with its data pin to the GPIO pin 4 and an error led is connected to the GPIO pin 23, it shall blink when there is an error.

The image illustrates a breadboard wiring setup with a Raspberry Pi. A DHT11 sensor (KY-015) is connected to the Raspberry Pi. The DHT11 is connected to 3V3, GND, and GPIO4. Additionally, an LED is wired from GPIO23 on the Raspberry Pi, with a resistor connected to ground, and is placed on the breadboard.

To address the sensor from node there is another dependency which has to be installed. The node-dht-sensor package uses the BCM2835 library. To install this library connect to your Raspberry Pi via ssh and start by downloading the current library version (1.57) after downloading unpack and install it:

1wget https://www.airspayce.com/mikem/bcm2835/bcm2835-1.57.tar.gz
2tar zxvf bcm2835-1.57.tar.gz
3cd bcm2835-1.57
4./configure
5make
6sudo make check
7sudo make install

With the BCM2835 library installed the project setup can continue. As you already did for the blinky app create a new folder ~/sensors01 in your home folder on the Raspberry Pi. This folder will be used as target to transfer the files over scp.

On your normal computer start a new project and add a package.json:

1{
2 "name": "sensors01",
3 "scripts": {
4 "start": "node index.js"
5 },
6 "dependencies": {
7 "axios": "^0.18.0",
8 "node-dht-sensor": "^0.0.34",
9 "onoff": "^3.2.2",
10 "sleep-promise": "^8.0.1",
11 "yargs": "^12.0.2"
12 }
13}

The listed dependencies are :

  • axios - a package for easier http requests
  • node-dht-sensor - used to read the DHT sensor
  • onoff - for easy access to the gpio pins
  • sleep-promise - awaitable sleep function
  • yargs - simplifies access to arguments used to start the program

As a start for your sensor reading program you can use this code:

1const sensorLib = require("node-dht-sensor");
2const Gpio = require("onoff").Gpio;
3const sleep = require("sleep-promise");
4const yargs = require("yargs");
5const axios = require("axios");
6
7const args = yargs.options({
8 backend: { alias: "b" },
9 interval: { alias: "i", default: 5000 },
10 verbose: {
11 alias: "v",
12 default: false,
13 boolean: true,
14 },
15}).argv;
16
17console.log(
18 `starting reading of sensor data with backend: ${args.backend} and interval: ${args.interval}`,
19);
20
21const errorLed = new Gpio(23, "out");
22
23// local state holding variable used to indicate some kind of error
24let deviceHasError = false;
25/**
26 * function to let an led connected to the pin 23 blink frantically
27 * runs as long as the `deviceHasError` state is true
28 */
29async function errorBlink() {
30 errorLed.writeSync(1);
31 await sleep(100);
32 errorLed.writeSync(0);
33 await sleep(100);
34
35 if (deviceHasError) {
36 errorBlink();
37 }
38}
39
40/**
41 * some data to describe the connected DHT sensor
42 * type can be 11 or 22, it depends on the device
43 * the number of the gpio pin connected to the data pin of the sensor
44 */
45const dhtSensor = {
46 type: 11,
47 pin: 4,
48 name: "Kalle's DHT11",
49};
50
51/**
52 * function which tries to send the given data to the server,
53 * which is set through the `--backend` start argument
54 * @param {*} params data to send to the server
55 */
56async function postDataToServer(params) {
57 try {
58 // TODO: send the data as JSON to the server
59 if (args.verbose) {
60 console.log("sent sensor data to server");
61 }
62 } catch (e) {
63 console.error("failed sending sensor data to server", e);
64 }
65}
66
67/**
68 * function which reads the sensor values and sends them to the server
69 * after waiting for the specified interval time it calls itself to run again
70 */
71async function readSensor() {
72 sensorLib.read(
73 dhtSensor.type,
74 dhtSensor.pin,
75 (error, temperature, humidity) => {
76 // TODO: check if there is an error
77 // TODO: if the sensor values are valid send them to the backend
78 },
79 );
80
81 // wait for the given interval
82 await sleep(args.interval);
83 // start over
84 readSensor();
85}
86
87// kick of the sensor reading
88readSensor();

Now it's time to bring some internet to the things, the program above needs a server to send the collected data to. For an easy start the server should be as simple as possible. I recommend using a library made for micro-services called micro.js, it lets you build single purpose servers easily.

To begin working on the server create another project and start with this package.json:

1{
2 "name": "sensorServer01",
3 "main": "index.js",
4 "scripts": {
5 "start": "micro"
6 },
7 "dependencies": {
8 "micro": "^9.3.3",
9 "ip": "^1.1.5"
10 }
11}

The listed dependencies are :

  • micro - package to create micro-services
  • ip - package to get simple access to own ip

As a starting point for the server you can use the following script:

1const { promisify } = require("util");
2const { json, send } = require("micro");
3const ip = require("ip");
4const fs = require("fs");
5
6const writeFileAsync = promisify(fs.writeFile);
7const existsFileAsync = promisify(fs.exists);
8
9const DATA_FILE = "./sensorReadings.json";
10
11/**
12 * tries to read the json data stored in the
13 * ./sensorReadings.json file, if it fails an
14 * empty array is returned
15 */
16async function readData() {
17 let data = [];
18 if (await existsFileAsync(DATA_FILE)) {
19 try {
20 data = require(DATA_FILE);
21 } catch (e) {
22 console.error("failed reading file", DATA_FILE, e);
23 }
24 }
25 return data;
26}
27
28/**
29 * Writes the collected data as a stringified json object
30 * to the ./sensorReadings.json file
31 * @param {Array<any>} data
32 */
33async function writeData(data) {
34 await writeFileAsync(DATA_FILE, JSON.stringify(data));
35}
36
37console.log("started sensor data collection service");
38console.log(
39 "running at ",
40 `http://${ip.address()}:${process.env.PORT || 3000}`,
41);
42
43/**
44 * If the server gets a POST request read the posted json data and store it
45 * if it is a GET request send the collected data to the client
46 * @param {import("http").IncomingMessage} req
47 * @param {import("http").ServerResponse} res
48 */
49module.exports = async function handleRequest(req, res) {
50 const data = await readData();
51
52 if (req.method === "GET") {
53 // TODO: send the collected data to the client
54 } else if (req.method === "POST") {
55 // TODO: add the newly collected data to the data array
56 // TODO: send a success code to the client
57 }
58};

Tasks

  • prepare the Raspberry Pi with the installation of the BCM2835 library
  • connect a DHT11 sensor with the Raspberry Pi
  • connect a LED with the Raspberry Pi as an error signal
  • extend the program running on the RPi to read temperature and humidity values from the DHT11 sensor
  • create a server to collect data posted to it
This AI-generated image shows a futuristic control room with a central holographic globe surrounded by workstations. The walls display interfaces for Wi-Fi, Bluetooth, Zigbee, and other connectivity technologies.

IoT — Communication protocols

Explore the various communication protocols used in IoT, focusing on MQTT for efficient machine-to-machine communication. This guide explains MQTT's lightweight binary protocol, its publish/subscribe model, and how to implement it using a message broker and Node.js.

Mailing List

If you want to receive updates on new posts, leave your email below.