30 Minutes or Less: Build a Wireless Sensor Network Using NodeMCU

Machinechat Jedi
The Startup
Published in
8 min readJun 25, 2020

--

“I want to have sensors everywhere!” In this article we’ll show you how to create a wireless sensor node using an inexpensive NodeMCU module.

NodeMCU is a tiny, low-cost WiFi-enabled microcontroller that supports direct connectivity to sensors via SPI, I2C, ADC, GPIO, etc. Programming of the module is made easier with support for the Arduino Integrated Development Environment (IDE). You can build up as many wireless sensor nodes as needed to create your wireless sensor network.

The wireless sensor nodes will send data to the Universal Sensor Hub that we showed you how to build in our prior article. We use the same sensor from the universal hub article, but feel free to experiment with other sensors — gas sensors, door switches, noise detectors, water level, soil moisture level, etc. The Universal Sensor Hub uses Machinechat JEDI One software running on the Raspberry Pi. JEDI One enables you to collect data from all the sensors and display the data on a dashboard accessible from any browser on the network.

Here is an example of a JEDI One system view of multiple sensors:

We will show you in just 4 steps, how to get a wireless sensor network started. A few items you will need:

  1. NodeMCU modules — less than $5 each
  2. BME280 Environmental sensor module w/ wires — $12 This one is used in example below
  3. Micro USB cable — $5
  4. Arduino IDE — Free
  5. Universal Sensor Hub with Machinechat JEDI One installed

Step 1: Setting up the Arduino IDE

Download the IDE here for your MAC, PC or Linux computer. If you are new to Arduino, please review this tutorial. Once you have it installed and running, you should see something like this:

Now install the libraries needed to talk to the BME280 environmental sensor. Select Tools -> Manage Libraries. Type bme into the search box. Install the Adafruit BME280 Library. Also install the supporting libraries it recommends. Here is a short video of this:

We also need the Arduino IDE to know how to talk to our NodeMCU module. Select:

  1. Arduino -> Preferences -> Additional Boards Manager URLs:
  2. Enter: http://arduino.esp8266.com/stable/package_esp8266com_index.json
  3. Click: OK

That window looks like this:

Finally, setup the details about your NodeMCU under Tools. This is important; if not correct, undesired behavior may occur! If you purchased the NodeMCU in the link above, the settings you want to select are:

Tools -> Board -> NodeMCU 1.0 (ESP-12E Module)
Tools -> Flash Size -> 4M (3M SPIFFS)
Tools -> CPU Frequency -> 80 Mhz
Tools -> Upload Speed -> 921600

Now, close the Arduino IDE program.

Step 2: Connecting the BME280 Sensor to the NodeMCU

Connect the NodeMCU to the recommended Waveshare BME280 module as follows:

Actual wiring:

Step 3: Loading, configuring, and running the software

Plug the micro USB cable into your PC and attach the NodeMCU to the other end. Important: The NodeMCU module will get power from the USB cable. Open the Arduino IDE. Your screen should look like this:

Download the sketch attached to this article, NodeMCU-BME280-JEDI-sketch.ino. Within the Arduino IDE click on FILE -> Open and then select the file you just downloaded. It will prompt to create a directory, agree to this.

Find the following lines of code in the sketch and change the “your-ssid” and “your-wifi-password” with the settings for your wireless router or access point.

// Wi-Fi settings - replace with your Wi-Fi SSID and password
const char* ssid = "your-ssid";
const char* password = "your-wifi-password";

Also, edit the line in the sketch with the IP address and port number for your Universal sensor hub running on the Raspberry Pi. The default HTTP listener for JEDI One is on port 8100. For this example we use 192.168.1.7:8100:

// IP address of server or Raspberry Pi running Machinechat JEDI software
// If you changed the JEDI port number, replace 8100 with the new port
const char* host = "192.168.1.7:8100";

Save the sketch by clicking on the download arrow button:

It is finally time to compile and load the sketch into the NodeMCU:

Success! Now that the code is in the NodeMCU flash, the Arduino IDE can be closed and the unit moved to another location. A USB charger can be used to power the NodeMCU; no need for the computer at this point.

The serial window in the video above shows that the information from the sensor is being successfully sent to our Universal Sensor hub. The LED on the NodeMCU will blink every five seconds when data is transmitted.

You can setup several of these NodeMCU sensor nodes to create a network and put them in various places to monitor several locations. Just make sure you change the target_id to a unique name for each NodeMCU. Here is what you will want to change:

You might choose to call them BMESensorNode2, BMESensorNode3… You can call them whatever you like, they just need to be unique for each NodeMCU. Then when you go to setup the dashboards and notifications in JEDI One, you will be able to tell which NodeMCU’s data you are working with.

We are now done setting up the NodeMCU module. The hard part is over and now we will take a moment to setup a JEDI One system view dashboard.

Step 4: Create a system view dashboard with Machinechat JEDI One to monitor your data

JEDI One allows you to view your data in two ways:

In this example, we will create a system view dashboard and add the temperature (bedroom) value from the wireless NodeMCU sensor and also the temperature (study) value from a sensor attached directly to our Universal Sensor Hub:

Notice how the target ID, BMESensorNode1 automatically showed up along with its the properties, tempC, humi, and pressure. These are being collected by the default HTTP listener. Our software below is sending the data via HTTP POST.

Congratulations! You’ve just learned how to set up and configure a wireless sensor in a NodeMCU environment. Now go ahead and add more sensors (just repeat steps 2 and 3, and remember to give each of your NodeMCU a unique target_id name)…and in no time, you can be the environmental data master of your universe (wherever it may be).

Check out the following links to learn how you can easily configure JEDI One to view, store and monitor your data in different ways:

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Arduino IDE sketch for this project:

// Code for NodeMCU boards with Espressif 8266 WiFi controller
// for measuring temperature, humidity, and pressure using the BME280 module
#include <ESP8266WiFi.h> // Include the Wi-Fi library
#include <ESP8266HTTPClient.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
// Some BME280 modules are strapped for address 0x76 - change line below as needed
#define I2C_ADDR 0x77
#define DELAYTIME 1000Adafruit_BME280 bme;// Wi-Fi settings - replace with your Wi-Fi SSID and password
const char* ssid = "your-ssid";
const char* password = "your-wifi-password";
// IP address of server or Raspberry Pi running Machinechat JEDI software
// If you changed the JEDI port number, replace 8100 with the new port
const char* host = "192.168.1.7:8100";
// This is the setup section and will only run one time
void setup() {
// Configure status LED on NodeMCU board
// Later, it will be programmed to blink every HTTP POST
pinMode(LED_BUILTIN, OUTPUT);
// Configure serial port for debug when NodeMCU board is connected
// to your computer or laptop using USB port
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
// Initiate Wi-Fi connection setup
WiFi.begin(ssid, password);
// Show status on serial monitor
Serial.print("Connecting to ");
Serial.print(ssid); Serial.println(" ...");
// Wait for Wi-Fi connection and show progress on serial monitor
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
// Configure BME280 Sensor Serial.println("Checking BME280");
unsigned status;
status = bme.begin(I2C_ADDR); if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(), 16);
Serial.print(" ID of 0xFF probably means a bad address\n");
while (1) delay(10); //***program will hang here if no valid sensor attached***
} else {
Serial.println("BME280 Detected");
}
}
// This is the main section and will loop continuosly
void loop() {
String postData; // This is the minimum amount of time to wait before
// reading the sensor
delay(DELAYTIME);
// Read the sensor and set variables
float tempC = bme.readTemperature();
float humi = bme.readHumidity();
float pressure = bme.readPressure() / 100.0F;
// Print the values to the serial monitor for debug and info
Serial.println('\n');
Serial.print(humi, 1);
Serial.print("\t\t");
Serial.print(tempC, 1);
Serial.print("\t\t");
Serial.println(pressure, 1);
// Build a string with data to send to JEDI. The format is
// {
// "context": {
// "target_id" : "Sensor1"
// },
// "data": {
// "metric1" : metric_value,
// "metric2" : metric_value
// }
// }
//
// Replace metric1 with what ever data metrics that you are
// sending to JEDI. Replace metric_value with the value of
// the metric. If you have more than one sensor, set the
// target_id with the name of the sensor.
postData = "{\"context\":{\"target_id\":\"BMESensorNode1\"}, \"data\":{\"tempC\":" + String(tempC) + ", " +
"\"humi\":" + String(humi) + ", " +
"\"pressure\":" + String(pressure) +
" }}";
if (WiFi.status() == WL_CONNECTED) { WiFiClient client;
HTTPClient http;
// Send the data to JEDI using HTTP.
String address = String("http://") + String(host) + String("/v1/data/mc");
http.begin(client, address);
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(postData);
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
const String& payload = http.getString();
Serial.print("received payload: ");
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); //Close connection // Blink the status LED
digitalWrite(LED_BUILTIN, LOW);
delay(500);
digitalWrite(LED_BUILTIN, HIGH);
} else {
Serial.println("Error in WiFi connection");
}
// Wait for 5 seconds before repeating the loop
delay(5000);

--

--

Machinechat Jedi
The Startup

Passionate about Raspberry Pi, BeagleBone and creating software that enables IoT developers and enthusiasts to deploy their projects faster — and beautifully.