In this article, you’ll learn how to use the ESP32 to communicate sensor data to ThingSpeak. We’ll use a BME280 sensor for demonstration reasons, but you can easily adapt the examples to use any other sensor.
PROJECT OVERVIEW
There are many ways to send sensor readings to ThingSpeak. In this tutorial, we’ll use one of the easiest ways—using the thingspeak-arduino library. This library provides methods to easily publish sensor readings to single fields or multiple fields.
PARTS REQUIRED
To complete this tutorial you need the following parts:
- BME280 sensor module-BME280, the precision sensor is soldered onto PCB. Not only the pressure and the temperature, this sensor can measure humidity. It uses both I2C and SPI (supports 3-, 4-wire SPI) interface. Humidity sensor and pressure sensor can be independently enabled / disabled.
- ESP32-The ESP32 is a low-cost, low-power microcontroller with Wi-Fi and Bluetooth built in. It succeeds the ESP8266, which is a low-cost Wi-Fi microprocessor with limited features.It includes a built-in antenna and RF balun, as well as a power amplifier, low-noise amplifiers, filters, and a power management module. The entire solution occupies the smallest amount of space on the printed circuit board. This board is used with TSMC 40nm low power technology 2.4 GHz dual-mode Wi-Fi and Bluetooth chips, which have the best power and RF attributes, are safe, dependable, and scalable to a variety of applications.
- Breadboard
- Jumper wires
Installing the ThingSpeak Library
The thingspeak-arduino library will be used to deliver sensor values to ThingSpeak. The Arduino Library Manager can be used to install this library. To manage libraries, go to Sketch > Include Library > Manage Libraries… and use the Library Manager to look for “ThingSpeak.” MathWorks’ ThingSpeak library should be installed.
Installing BME280 Libraries
We’ll publish sensor readings from a BME280 sensor. So, you also need to install the libraries to interface with the BME280 sensor.
- Adafruit_BME280 library
- Adafruit_Sensor library
You can install the libraries using the Arduino Library Manager. Go to Sketch > Include Library > Manage Libraries and search for the library name.
Installing Libraries (VS Code + PlatformIO)
If you’re using VS Code with the PlatformIO extension, copy the following to the platformio.ini file to include the libraries.
lib_deps = mathworks/ThingSpeak@^2.0.0
adafruit/Adafruit Unified Sensor @ ^1.1.4
adafruit/Adafruit BME280 Library @ ^2.1.2
SCHEMATIC
We’re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP32 SCL (GPIO 22) and SDA (GPIO 21) pins.
ThingSpeak – Getting Started
Go to ThingSpeak and click the “Get Started For Free” button to create a new account. This account is linked to a Mathworks account.
Creating New Channel
After your account is ready, sign in, open the “Channels” tab and select “My Channels“.
Press the “New Channel” button to create a new channel.
Type a name for your channel and add a description. In this example, we’ll just publish the temperature.
click the Save Channel button to create and save your channel.
Customizing Chart
The chart can be customized, go to your Private View tab and click on the edit icon.
You can give a title to your chart, customize the background color, x and y axis, and much more.
When you’re done, press the “Save” button.
API Key
To send values from the ESP32 to ThingSpeak, you need the Write API Key. Open the “API Keys”
Tab and copy the Write API Key to a safe place because we’ll need it in a moment.
CODE
#include <WiFi.h> #include "ThingSpeak.h" #include <Adafruit_BME280.h> #include <Adafruit_Sensor.h> const char* ssid = "REPLACE_WITH_YOUR_SSID"; // your network SSID (name) const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // your network password WiFiClient client; unsigned long myChannelNumber = X; const char * myWriteAPIKey = "XXXXXXXXXXXXXXXX"; // Timer variables unsigned long lastTime = 0; unsigned long timerDelay = 30000; // Variable to hold temperature readings float temperatureC; //uncomment if you want to get temperature in Fahrenheit //float temperatureF; // Create a sensor object Adafruit_BME280 bme; //BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL) void initBME(){ if (!bme.begin(0x76)) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1); } }
To make the code work, you need to insert your network credentials in the following variables:
const char* ssid = “REPLACE_WITH_YOUR_SSID”;
const char* password = “REPLACE_WITH_YOUR_PASSWORD”;
You need to insert the number of the channel that you’re publishing to. If you only have one channel created in ThingSpeak, the channel number is 1. Otherwise, you can see the number of the channel on the Private View tab.
unsigned long myChannelNumber = 1;
Finally, you need to insert the Write API key you’ve gotten from the previous steps:
const char * myWriteAPIKey = “XXXXXXXXXXXXXXXX”;
How the Code Works
First, you need to include the necessary libraries.
#include <WiFi.h>
#include “ThingSpeak.h”
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
Insert your network credentials in the following variables:
const char* ssid = “REPLACE_WITH_YOUR_SSID”;
const char* password = “REPLACE_WITH_YOUR_PASSWORD”;
Create a Wi-Fi client to connect to ThingSpeak.
WiFiClient client;
Insert your channel number as well as your write API key:
unsigned long myChannelNumber = 1;
const char * myWriteAPIKey = “XXXXXXXXXXXXXXXX”;
In the timerDelay variable insert how frequently you want to publish readings. In this case, we’re publishing readings every 30 seconds (30000 milliseconds). You can change this delay time if you want.
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
The temperatureC variable holds the temperature value in Celsius degrees.
float temperatureC;
If you want to get the temperature in Fahrenheit degrees, uncomment the following line.
//float temperatureF;
Create an Adafruit_BME280 object called bme on the default ESP32 pins.
Adafruit_BME280 bme; //BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
The initBME() function initializes the BME280 sensor.
void initBME(){
if (!bme.begin(0x76)) {
Serial.println(“Could not find a valid BME280 sensor, check wiring!”);
while (1);
}
}
In the setup(), initialize the Serial Monitor:
Serial.begin(115200); //Initialize serial
Initialize the BME280 sensor.
initBME();
Set the ESP32 as a Wi-Fi station:
WiFi.mode(WIFI_STA);
Initialize ThingSpeak:
ThingSpeak.begin(client); // Initialize ThingSpeak
In the loop(), connect or reconnect to Wi-Fi in case the connection was lost:
// Connect or reconnect to WiFi
if(WiFi.status() != WL_CONNECTED){
Serial.print(“Attempting to connect”);
while(WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, password);
delay(5000);
}
Serial.println(“\nConnected.”);
}
Get a new temperature reading and print it in the Serial Monitor:
temperatureC = bme.readTemperature();
Uncomment the following lines if you want to get the temperature in Fahrenheit degrees.
/*temperatureF = 1.8 * bme.readTemperature() + 32;
Serial.print(“Temperature (ºC): “);
Serial.println(temperatureF);*/
Finally, write to ThingSpeak. You can use the writeField() method that accepts as arguments:
- the channel number;
- the field number (in our case, we just have one field);
- the value you want to publish (temperatureC or temperatureF);
- your write API key.
This function returns the code 200 if it has succeeded in publishing the readings.
int x = ThingSpeak.writeField(myChannelNumber, 1, temperatureC, myWriteAPIKey);
if(x == 200){
Serial.println(“Channel update successful.”);
}
else{
Serial.println(“Problem updating channel. HTTP error code ” + String(x));
}
If you want to publish your readings in Fahrenheit degrees, uncomment the following line in the code:
//int x = ThingSpeak.writeField(myChannelNumber, 1, temperatureF, myWrit
DEMONSTRATION
Upload the code to your board after inputting your network credentials, channel number, and API key.
Using a baud rate of 115200, open the Serial Monitor and push the on-board RST button. It should connect to Wi-Fi after 30 seconds and begin reporting the readings to ThingSpeak.
Go to your ThingSpeak account to the channel we’ve just created, and we’ll see the temperature readings being published and plotted on the chart.
Now, you can get access to those readings from anywhere in the world by accessing your ThingSpeak account.
Sending Multiple Fields (Temperature, Humidity, and Pressure)
We’ll learn how to send multiple fields (more than one value at a time) in this part. We’ll send temperature, humidity, and pressure values.
Enable Multiple Fields – ThingSpeak
To begin, we’ll need to expand your ThingSpeak account by adding more fields. This is straightforward. You can add as many fields as you wish to your Channel Settings. We’ve added two extra fields in this case, one for humidity and the other for pressure.
Finally, save the channel—click the Save Channel button.
You should now see three charts under the Private View tab. Add a title and axis labels to the newly produced charts.
ESP32 Write Multiple Fields to ThingSpeak – Code
The following code sends multiple fields to ThingSpeak (temperature, humidity, and pressure from the BME280 sensor).
#include <WiFi.h> #include "ThingSpeak.h" #include <Adafruit_BME280.h> #include <Adafruit_Sensor.h> const char* ssid = "REPLACE_WITH_YOUR_SSID"; // your network SSID (name) const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // your network password WiFiClient client; unsigned long myChannelNumber = X; const char * myWriteAPIKey = "XXXXXXXXXXXXXXXX"; // Timer variables unsigned long lastTime = 0; unsigned long timerDelay = 30000; // Variable to hold temperature readings float temperatureC; float humidity; float pressure; //uncomment if you want to get temperature in Fahrenheit //float temperatureF; // Create a sensor object Adafruit_BME280 bme; //BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL) void initBME(){ if (!bme.begin(0x76)) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1); } } void setup() { Serial.begin(115200); //Initialize serial initBME(); WiFi.mode(WIFI_STA); ThingSpeak.begin(client); // Initialize ThingSpeak } void loop() { if ((millis() - lastTime) > timerDelay) { // Connect or reconnect to WiFi if(WiFi.status() != WL_CONNECTED){ Serial.print("Attempting to connect"); while(WiFi.status() != WL_CONNECTED){ WiFi.begin(ssid, password); delay(5000); } Serial.println("\nConnected."); } // Get a new temperature reading temperatureC = bme.readTemperature(); Serial.print("Temperature (ºC): "); Serial.println(temperatureC); humidity = bme.readHumidity(); Serial.print("Humidity (%): "); Serial.println(humidity); pressure = bme.readPressure() / 100.0F; Serial.print("Pressure (hPa): "); Serial.println(pressure); //uncomment if you want to get temperature in Fahrenheit /*temperatureF = 1.8 * bme.readTemperature() + 32; Serial.print("Temperature (ºC): "); Serial.println(temperatureF);*/ // set the fields with the values ThingSpeak.setField(1, temperatureC); //ThingSpeak.setField(1, temperatureF); ThingSpeak.setField(2, humidity); ThingSpeak.setField(3, pressure); // Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different // pieces of information in a channel. Here, we write to field 1. int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); if(x == 200){ Serial.println("Channel update successful."); } else{ Serial.println("Problem updating channel. HTTP error code " + String(x)); } lastTime = millis(); } }
This code is very similar to the previous one, but sends multiple fields.Frist, create variables to hold the sensor readings:
float temperatureC;
float humidity;
float pressure;
In the loop(), get new temperature, humidity and pressure readings:
// Get a new temperature reading
temperatureC = bme.readTemperature();
Serial.print(“Temperature (ºC): “);
Serial.println(temperatureC);
humidity = bme.readHumidity();
Serial.print(“Humidity (%): “);
Serial.println(humidity);
pressure = bme.readPressure() / 100.0F;
Serial.print(“Pressure (hPa): “);
Serial.println(pressure);
You need to assign a value to each field.. The following lines assign the corresponding values to each field using the setField() method—it accepts as arguments the field number and the value:
// set the fields with the values
ThingSpeak.setField(1, temperatureC);
//ThingSpeak.setField(1, temperatureC);
ThingSpeak.setField(2, humidity);
ThingSpeak.setField(3, pressure);
Finally, use the writeFields() method and set as arguments the channel number and the write API key:
int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
CONCLUSION
We learnt how to use the ESP32 and the thingspeak-arduino library to broadcast readings from a BME280 sensor to ThingSpeak in this lesson.