Overview
In this IoT Based Project, we will interface BME680 Sensor with ESP32 or ESP8266 WiFi Module. We will make our own Weather Station & IAQ (Index of Air Quality) Monitoring System. The project is based on MQTT protocol using ESP32/ESP8266 & BME680 integrated Environmental Sensor. The MQTT platform that we will use is the Ubidots. Using the Ubidots platform we can send data to the cloud from any Internet-enabled device.
MQTT is a lightweight protocol very popular for IoT devices. MQTT allows you to send commands to regulate outputs, read unpublished data from the sensor node, and far more. Therefore, it makes it very easy to establish communication between multiple devices. The BME680 measures temperature, humidity, altitude, pressure, dew point & Air Quality Index (AQI) and publishes it to the Ubidots cloud over MQTT. The Ubidots dashboard will display the real-time sensor data in beautiful widgets.
On the hardware part, we just need a BME680 Sensor and ESP8266 or ESP32 WiFi Module. A 4 wire I2C Connection between the sensor and controller is enough for hardware setup. The ESP32/ESP8266 connects to the WiFi Network and using the Ubidots API key, the environmental data are uploaded to Ubidots dashboard after a fixed interval. You can access the dashboard either from the computer or using a smartphone from any part of the world. To learn about the basics of the BME680 Sensor you can check the Arduino BME680 interfacing article.
Bill of Materials
The list of components that we need for making this IoT project is given below. You can purchase all the components from the given Amazon links.
| S.N. | Components Name | Quantity | Purchase Links |
|---|---|---|---|
| 1 | ESP32 WiFi Module | 1 | Amazon | AliExpress |
| 2 | ESP8266 WiFi Module | 1 | Amazon | AliExpress |
| 3 | BME680 Sensor | 1 | Amazon | AliExpress |
| 4 | Connecting Wires | 10 | Amazon | AliExpress |
| 5 | Breadboard | 1 | Amazon | AliExpress |
BME680 Integrated Environmental Sensor
The BME680 is a digital 4-in-1 sensor with gas, humidity, pressure and temperature measurement based on proven sensing principles. The BME680 is the upgraded and better version of its previous versions like BMP180, BMP280 or BME280. The gas sensor on the BME680 can detect a wide variety of volatile organic compounds to monitor indoor air quality. The sensor has high-linearity and high-accuracy.
The BME680 is specially developed for mobile applications and wearables where size and low power consumption are critical requirements. In order to measure air quality, the gas sensor within the BME680 can detect a broad range of gases such as volatile organic compounds (VOC).
The sensor operates between 1.7V to 3.6V. The standby power consumption of this module is 0.29 to 0.8 uA and while in sleep mode the power consumption is between 0.15 to 1 uA. The temperature measurement range of the BME680 Sensor is -40~+85℃. And the humidity measurement range is 0-100%. It can measure the Air quality index (IAQ) from 0-500 PPM.
The default I2C Address of the sensor is 0x76 but it can be changed to 0x77 simply by connecting SDO to GND.To learn more about the BME680 Sensor, you can check BME680 Datasheet.
Hardware Setup & Circuit Assembly
ESP32 & BME680 Connection
The connection diagram of the BME680 Sensor with ESP32 Board is given below. You can use the breaboard to assemble the circuit.
Connect the VCC & GND pin of BME680 Sensor to ESP32 3.3V & GND Pin. Similarly connect the BME680 SDA & SCL Pin to ESP32 GPIO21 & GPIO22 Pin respectively. You can power on the device using a 5V Micro-USB port of ESP32 or 3.7V Lithium-Ion Battery.
ESP8266 & BME680 Connection
The connection diagram of the BME680 Sensor with NodeMCU ESP8266 Board is given below. You can use the breaboard to assemble the circuit.
Connect the VCC & GND pin of BME680 Sensor to NodeMCU ESP8266 3.3V & GND Pin. Similarly, connect the BME680 SDA & SCL Pin to ESP8266 D2 & D1 Pin respectively. You can power on the device using a 5V Micro-USB port of NodeMCU Board or 3.7V Lithium-Ion Battery.
Setting Up Ubidots
We need to setup the Ubidots dashboard in order to recieve the BME680 data from ESP32 or ESP8266 MQTT. In order to set up Ubidots, visit https://ubidots.com/ & create a New Account using your email address.
After login into Ubidots Dashboard, we need an API Key. To get the API key, click on the top right of the dashboard on the profile option. You will see an option called “API Credentials”. Click on the option.
Now when you click on Default Token and copy the API Token. This API Token is required in the code.
Source Code: ESP32 BME680 Weather Station & IAQ Monitoring on MQTT
The Source Code/Program for BME680 with ESP32 or ESP8266 is given below. But before that you will need few libraries. You can download the ibraries from the following link.
1. PubSubClient Library: https://github.com/knolleary/pubsubclient
2. BME680 Adafruit Library: https://github.com/adafruit/Adafruit_BME680
3. Adafruit Unified Sensor Library: https://github.com/adafruit/Adafruit_Sensor
|
1 2 |
#define WIFISSID "***************************" // Put your WifiSSID here #define PASSWORD "***************************" // Put your wifi password here |
Change the WiFi SSID & Password from the above lines and replace it with your SSID & Password.
|
1 |
#define TOKEN "BBFF-nXv****************8HSCWBI27sv" // Put your Ubidots' TOKEN |
Change the Ubidots Authentication Token from here. Replace with the token that you got while creating the Ubidots account as explained above.
Source Code: ESP32 BME680 MQTT
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
#include <Wire.h> #include <WiFi.h> #include <PubSubClient.h> #include <Adafruit_Sensor.h> #include "Adafruit_BME680.h" #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME680 bme; // I2C #define WIFISSID "realme C15" // Put your WifiSSID here #define PASSWORD "12341234" // Put your wifi password here #define TOKEN "BBFF-***************CWBI27sv" // Put your Ubidots' TOKEN #define MQTT_CLIENT_NAME "ESP32_BME680_Station" // MQTT client Name, please enter your own 8-12 alphanumeric character ASCII string; /**************************************** Define Constants ****************************************/ #define VARIABLE_LABEL1 "Temperature" // Assing the variable label #define VARIABLE_LABEL2 "Humidity" // Assing the variable label #define VARIABLE_LABEL3 "Pressure" #define VARIABLE_LABEL4 "Altitude" #define VARIABLE_LABEL5 "DewPoint" #define VARIABLE_LABEL6 "Gas" #define DEVICE_LABEL "ESP32" char mqttBroker[] = "industrial.api.ubidots.com"; char payload[1000]; char topic1[150]; char topic2[150]; char topic3[150]; char topic4[150]; char topic5[150]; char topic6[150]; // Space to store values to send char str_Temperature[10]; char str_Humidity[10]; char str_Pressure[10]; char str_Altitude[10]; char str_DewPoint[10]; char str_Gas[10]; /**************************************** Auxiliar Functions ****************************************/ WiFiClient ubidots; PubSubClient client(ubidots); void callback(char* topic, byte* payload, unsigned int length) { char p[length + 1]; memcpy(p, payload, length); p[length] = NULL; String message(p); Serial.write(payload, length); Serial.println(topic); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.println("Attempting MQTT connection..."); // Attemp to connect if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) { Serial.println("Connected"); } else { Serial.print("Failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2 seconds"); // Wait 2 seconds before retrying delay(2000); } } } /**************************************** Main Functions ****************************************/ void setup() { Serial.begin(115200); while (!Serial); Serial.println(F("BME680 test")); if (!bme.begin()) { Serial.println("Could not find a valid BME680 sensor, check wiring!"); while (1); } // Set up oversampling and filter initialization bme.setTemperatureOversampling(BME680_OS_8X); bme.setHumidityOversampling(BME680_OS_2X); bme.setPressureOversampling(BME680_OS_4X); bme.setIIRFilterSize(BME680_FILTER_SIZE_3); bme.setGasHeater(320, 150); // 320*C for 150 ms WiFi.begin(WIFISSID, PASSWORD); Serial.println(); Serial.print("Waiting for WiFi Connection .............."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi Connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); client.setServer(mqttBroker, 1883); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } if (! bme.performReading()) { Serial.println("Failed to perform reading :("); return; } float temperature = (bme.temperature); float humidity = (bme.humidity); float pressure = (bme.pressure / 100.0); float altitude = (bme.readAltitude(SEALEVELPRESSURE_HPA)); double dewPoint = (dewPointFast(temperature, humidity)); float gas = (bme.gas_resistance / 1000.0); Serial.print("Temperature = "); Serial.print(temperature); Serial.println(" *C"); Serial.print("Humidity = "); Serial.print(humidity); Serial.println(" %"); Serial.print("Pressure = "); Serial.print(pressure); Serial.println(" hPa"); Serial.print("Approx. Altitude = "); Serial.print(altitude); Serial.println(" m"); Serial.print("Dew Point = "); Serial.print(dewPoint); Serial.println(" *C"); Serial.print("Gas = "); Serial.print(gas); Serial.println(" KOhms"); dtostrf(temperature, 4, 2, str_Temperature); dtostrf(humidity, 4, 2, str_Humidity); dtostrf(pressure, 4, 2, str_Pressure); dtostrf(altitude, 4, 2, str_Altitude); dtostrf(dewPoint, 4, 2, str_DewPoint); dtostrf(gas, 4, 2, str_Gas); sprintf(topic1, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL1); sprintf(payload, "%s {\"value\": %s}}", payload, str_Temperature); Serial.println("Publishing temperature to Ubidots Cloud"); client.publish(topic1, payload); sprintf(topic2, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL2); sprintf(payload, "%s {\"value\": %s}}", payload, str_Humidity); Serial.println("Publishing humidity to Ubidots Cloud"); client.publish(topic2, payload); sprintf(topic3, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL3); sprintf(payload, "%s {\"value\": %s}}", payload, str_Pressure); Serial.println("Publishing Pressure data to Ubidots Cloud"); client.publish(topic3, payload); sprintf(topic4, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL4); sprintf(payload, "%s {\"value\": %s}}", payload, str_Altitude); Serial.println("Publishing Altitude data to Ubidots Cloud"); client.publish(topic4, payload); sprintf(topic5, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL5); sprintf(payload, "%s {\"value\": %s}}", payload, str_DewPoint); Serial.println("Publishing Dew Point data to Ubidots Cloud"); client.publish(topic5, payload); sprintf(topic6, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL6); sprintf(payload, "%s {\"value\": %s}}", payload, str_Gas); Serial.println("Publishing Gas data to Ubidots Cloud"); client.publish(topic6, payload); Serial.println(); client.loop(); delay(5000); } double dewPointFast(double celsius, double humidity) { double a = 17.271; double b = 237.7; double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01); double Td = (b * temp) / (a - temp); return Td; } |
Source Code: ESP8266 BME680 MQTT
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
#include <Wire.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <Adafruit_Sensor.h> #include "Adafruit_BME680.h" #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME680 bme; // I2C #define WIFISSID "realme C15" // Put your WifiSSID here #define PASSWORD "12341234" // Put your wifi password here #define TOKEN "BBF************************WBI27sv" // Put your Ubidots' TOKEN #define MQTT_CLIENT_NAME "ESP8266_BME680_Station" // MQTT client Name, please enter your own 8-12 alphanumeric character ASCII string; /**************************************** Define Constants ****************************************/ #define VARIABLE_LABEL1 "Temperature" // Assing the variable label #define VARIABLE_LABEL2 "Humidity" // Assing the variable label #define VARIABLE_LABEL3 "Pressure" #define VARIABLE_LABEL4 "Altitude" #define VARIABLE_LABEL5 "DewPoint" #define VARIABLE_LABEL6 "Gas" #define DEVICE_LABEL "ESP8266" char mqttBroker[] = "industrial.api.ubidots.com"; char payload[1000]; char topic1[150]; char topic2[150]; char topic3[150]; char topic4[150]; char topic5[150]; char topic6[150]; // Space to store values to send char str_Temperature[10]; char str_Humidity[10]; char str_Pressure[10]; char str_Altitude[10]; char str_DewPoint[10]; char str_Gas[10]; /**************************************** Auxiliar Functions ****************************************/ WiFiClient ubidots; PubSubClient client(ubidots); void callback(char* topic, byte* payload, unsigned int length) { char p[length + 1]; memcpy(p, payload, length); p[length] = NULL; String message(p); Serial.write(payload, length); Serial.println(topic); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.println("Attempting MQTT connection..."); // Attemp to connect if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) { Serial.println("Connected"); } else { Serial.print("Failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2 seconds"); // Wait 2 seconds before retrying delay(2000); } } } /**************************************** Main Functions ****************************************/ void setup() { Serial.begin(115200); while (!Serial); Serial.println(F("BME680 test")); if (!bme.begin()) { Serial.println("Could not find a valid BME680 sensor, check wiring!"); while (1); } // Set up oversampling and filter initialization bme.setTemperatureOversampling(BME680_OS_8X); bme.setHumidityOversampling(BME680_OS_2X); bme.setPressureOversampling(BME680_OS_4X); bme.setIIRFilterSize(BME680_FILTER_SIZE_3); bme.setGasHeater(320, 150); // 320*C for 150 ms WiFi.begin(WIFISSID, PASSWORD); Serial.println(); Serial.print("Waiting for WiFi Connection .............."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi Connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); client.setServer(mqttBroker, 1883); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } if (! bme.performReading()) { Serial.println("Failed to perform reading :("); return; } float temperature = (bme.temperature); float humidity = (bme.humidity); float pressure = (bme.pressure / 100.0); float altitude = (bme.readAltitude(SEALEVELPRESSURE_HPA)); double dewPoint = (dewPointFast(temperature, humidity)); float gas = (bme.gas_resistance / 1000.0); Serial.print("Temperature = "); Serial.print(temperature); Serial.println(" *C"); Serial.print("Humidity = "); Serial.print(humidity); Serial.println(" %"); Serial.print("Pressure = "); Serial.print(pressure); Serial.println(" hPa"); Serial.print("Approx. Altitude = "); Serial.print(altitude); Serial.println(" m"); Serial.print("Dew Point = "); Serial.print(dewPoint); Serial.println(" *C"); Serial.print("Gas = "); Serial.print(gas); Serial.println(" KOhms"); dtostrf(temperature, 4, 2, str_Temperature); dtostrf(humidity, 4, 2, str_Humidity); dtostrf(pressure, 4, 2, str_Pressure); dtostrf(altitude, 4, 2, str_Altitude); dtostrf(dewPoint, 4, 2, str_DewPoint); dtostrf(gas, 4, 2, str_Gas); sprintf(topic1, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL1); sprintf(payload, "%s {\"value\": %s}}", payload, str_Temperature); Serial.println("Publishing temperature to Ubidots Cloud"); client.publish(topic1, payload); sprintf(topic2, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL2); sprintf(payload, "%s {\"value\": %s}}", payload, str_Humidity); Serial.println("Publishing humidity to Ubidots Cloud"); client.publish(topic2, payload); sprintf(topic3, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL3); sprintf(payload, "%s {\"value\": %s}}", payload, str_Pressure); Serial.println("Publishing Pressure data to Ubidots Cloud"); client.publish(topic3, payload); sprintf(topic4, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL4); sprintf(payload, "%s {\"value\": %s}}", payload, str_Altitude); Serial.println("Publishing Altitude data to Ubidots Cloud"); client.publish(topic4, payload); sprintf(topic5, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL5); sprintf(payload, "%s {\"value\": %s}}", payload, str_DewPoint); Serial.println("Publishing Dew Point data to Ubidots Cloud"); client.publish(topic5, payload); sprintf(topic6, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL6); sprintf(payload, "%s {\"value\": %s}}", payload, str_Gas); Serial.println("Publishing Gas data to Ubidots Cloud"); client.publish(topic6, payload); Serial.println(); client.loop(); delay(5000); } double dewPointFast(double celsius, double humidity) { double a = 17.271; double b = 237.7; double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01); double Td = (b * temp) / (a - temp); return Td; } |
Test Results & Further Setting of Ubidots Dashboard
The above code for ESP32 & BME680 for MQTT Ubidots fulfills all the requirements of the project. You can either interface the BME680 with ESP32 or with ESP8266. You can upload the code to the WiFi Module. Once the code is uploaded, the ESP32/ESP8266 board will try connecting to the local programmed WiFi Network. Once connected you can open the Serial Monitor.
The Serial monitor will display the Temperature, Humidity, Pressure, Altitude, Dew Point as well as IAQ (Index of Air Quality). So, not only you can measure the environmental parameter but also the IAQ using ESP32 & BME680. If there is a successful wifi connection and further a connection to Ubidots, the data will be uploaded automatically after every set interval.
Initially no devices will be displayed on Ubidots dashboard. But as soon as the device is connected to a computer on powered on, you will see a device appearing on the Ubidots device Section.
Now click on the device that is displayed on Ubidots Dashboard. In my case, esp32 is displayed as I am using ESP32 & BME680 MQTT Connection. In this dashboard, you will see the data for temperature, humidity, pressure, altitude, dew point, and IAQ. The MQTT connection iS real-time. So data changes after a certain interval.
Now, go back to the dashboard. On the top right side of the dashboard click on the “+” Symbol. You will see there are so many widgets. You can click and create a widget display for all individual parameters from temperature to IAQ. For example, you can select Gauge for displaying Humidity.
After selecting gauge or any other widget, select the variable from the list of 6 variable by clicking on “Add Variables“. Then give it any name and click on the green button to continue.
Do the same thing for all other remaining 5 variables as well. Finally, after designing the dashboard with the help of a widget, you will get a beautiful real-time dashboard as shown in the image below.
You can also visit the mobile version of the Ubidots dashboard, the mobile screen will also show the BME680 logged data on widgets display.
So, so this how we can interface BME680 integrated Environmental Sensor with ESP32 or ESP8266 Wifi Module & measure IAQ and all other environmental parameters. Similarly, sending the data to the Ubidots dashboard using MQTT Broker requires a great level of programming skills. You can send data from the other sensors to the Ubidots platform using the same method.






















2 Comments
Hi! It was really fun to complete, now I have a climate station home. I added some timing between measurements to stay within Ubidots free tier measurements limit, and a visual confirmation of when the measurements are done. If anyone finds value in this, here is my code https://github.com/solracid/Arduino-BME680-Weather-Station Thanks for sharing this project.
what should i do if i want to add 2 more variables?