,

Indoor weather station with MQTT, V2

Posted by

I just created for you an Indoor weather station with MQTT, V2. It comprises a Xiao ESP32-C6 from SeeedStudio and a ENS160+BME280 sensor kit from DFRobot. Objective is to have an app at my cellphone (MQTT Dash) to look into environmental values from my living room.

Such values include local temperature, humidity, atmospheric pressure (from BME280). Also from ENS160 comes TVOC (volatile organic compounds), CO2 (carbon dioxide) and AQI (air quality). I programmed the ESP32 to relay such variables to Adafruit.io every 60 seconds. You guys have seen my V1 weather station here, featuring a single HTU21D. Up until now it was working 24/7 inside home.

ENS160+BME280+ESP32 weather station
ENS160+BME280+ESP32 weather station

I made it using this platform and PCB, which is very simple. All there is to it is a Xiao ESP32-C6, one USB-A male connector and four pins for any i2c device circuit board. It was thought and planned fro the HTU21D from Aliexpress but it fits any i2c device really.

The sensors and schematic

I am using this sensor combo from DFrobot, comprising an ENS160 and a BME280, giving me all the measurements I commented above already. The fact that it uses i2c makes wire harnessing (and PCB design) a lot easier to do.

Schematic diagram is below for you to replicate and mix/match.

ENS160+BME280+ESP32 schematic diagram
ENS160+BME280+ESP32 schematic diagram

Code/firmware

Full code for this example is in this Github link and also below. As stated above, what I do is every 60 seconds relay sensor information from the ESP32 to Adafruit.io. Please add your WiFi and Adafruit.io information to the sketch in the fields with the ” “.

#include <WiFi.h>
#include "WiFiClientSecure.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <DFRobot_ENS160.h>

#define SEALEVELPRESSURE_HPA (1013.25)
DFRobot_ENS160_I2C ENS160(&Wire, /*I2CAddr*/ 0x53);
Adafruit_BME280 bme; // I2C

/************************* WiFi Access Point *********************************/

#define WLAN_SSID ""
#define WLAN_PASS ""

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"

// Using port 8883 for MQTTS
#define AIO_SERVERPORT  8883

// Adafruit IO Account Configuration
// (to obtain these values, visit https://io.adafruit.com and click on Active Key)
#define AIO_USERNAME ""
#define AIO_KEY      ""

/************ Global State (you don't need to change this!) ******************/

#include <Wire.h>


// WiFiFlientSecure for SSL/TLS support
WiFiClientSecure client;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

// io.adafruit.com root CA
const char* adafruitio_root_ca = \
      "-----BEGIN CERTIFICATE-----\n"
      "MIIEjTCCA3WgAwIBAgIQDQd4KhM/xvmlcpbhMf/ReTANBgkqhkiG9w0BAQsFADBh\n"
      "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
      "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
      "MjAeFw0xNzExMDIxMjIzMzdaFw0yNzExMDIxMjIzMzdaMGAxCzAJBgNVBAYTAlVT\n"
      "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
      "b20xHzAdBgNVBAMTFkdlb1RydXN0IFRMUyBSU0EgQ0EgRzEwggEiMA0GCSqGSIb3\n"
      "DQEBAQUAA4IBDwAwggEKAoIBAQC+F+jsvikKy/65LWEx/TMkCDIuWegh1Ngwvm4Q\n"
      "yISgP7oU5d79eoySG3vOhC3w/3jEMuipoH1fBtp7m0tTpsYbAhch4XA7rfuD6whU\n"
      "gajeErLVxoiWMPkC/DnUvbgi74BJmdBiuGHQSd7LwsuXpTEGG9fYXcbTVN5SATYq\n"
      "DfbexbYxTMwVJWoVb6lrBEgM3gBBqiiAiy800xu1Nq07JdCIQkBsNpFtZbIZhsDS\n"
      "fzlGWP4wEmBQ3O67c+ZXkFr2DcrXBEtHam80Gp2SNhou2U5U7UesDL/xgLK6/0d7\n"
      "6TnEVMSUVJkZ8VeZr+IUIlvoLrtjLbqugb0T3OYXW+CQU0kBAgMBAAGjggFAMIIB\n"
      "PDAdBgNVHQ4EFgQUlE/UXYvkpOKmgP792PkA76O+AlcwHwYDVR0jBBgwFoAUTiJU\n"
      "IBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG\n"
      "AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB\n"
      "BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1Ud\n"
      "HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds\n"
      "b2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW\n"
      "HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEB\n"
      "AIIcBDqC6cWpyGUSXAjjAcYwsK4iiGF7KweG97i1RJz1kwZhRoo6orU1JtBYnjzB\n"
      "c4+/sXmnHJk3mlPyL1xuIAt9sMeC7+vreRIF5wFBC0MCN5sbHwhNN1JzKbifNeP5\n"
      "ozpZdQFmkCo+neBiKR6HqIA+LMTMCMMuv2khGGuPHmtDze4GmEGZtYLyF8EQpa5Y\n"
      "jPuV6k2Cr/N3XxFpT3hRpt/3usU/Zb9wfKPtWpoznZ4/44c1p9rzFcZYrWkj3A+7\n"
      "TNBJE0GmP2fhXhP1D/XVfIW/h0yCJGEiV9Glm/uGOa3DXHlmbAcxSyCRraG+ZBkA\n"
      "7h4SeM6Y8l/7MBRpPCz6l8Y=\n"
      "-----END CERTIFICATE-----\n";

/****************************** Feeds ***************************************/

long oldtime;
long oldtimeled;

// Setup a feed called 'test' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Publish temperaturereadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperaturereadings");
Adafruit_MQTT_Publish humidityreadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidityreadings");
Adafruit_MQTT_Publish pressurereadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/pressurereadings");
Adafruit_MQTT_Publish aqireadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/aqireadings");
Adafruit_MQTT_Publish tvocreadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tvocreadings");
Adafruit_MQTT_Publish eco2readings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/eco2readings");
/*************************** Sketch Code ************************************/

void setup() {
  Serial.begin(115200);
  pinMode(15, OUTPUT);
  delay(10);

  Serial.println(F("Adafruit IO MQTTS (SSL/TLS) Example"));

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  delay(1000);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  delay(2000);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());

  // Set Adafruit IO's root CA
  client.setCACert(adafruitio_root_ca);

 bme.begin(0x76, &Wire);
 while( NO_ERR != ENS160.begin() ){
      Serial.println("Communication with device ENS160, please check connection");
      delay(3000);
    } 
  ENS160.setPWRMode(ENS160_STANDARD_MODE);
  ENS160.setTempAndHum(/*temperature=*/25.0, /*humidity=*/50.0);

}

uint32_t x=0;

void loop() {

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi not connected! Attempting reconnect...");
    WiFi.disconnect();
    WiFi.begin(WLAN_SSID, WLAN_PASS);
    unsigned long startAttemptTime = millis();

    // Wait until connected or timeout (10 seconds)
    while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 10000) {
      delay(500);
      Serial.print(".");
    }

    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Reconnected to WiFi!");
    } else {
      Serial.println("Failed to reconnect WiFi. Will retry later.");
      return; // Skip rest of loop if WiFi isn't working
    }
  }

  if(millis() - oldtimeled > 200){
    oldtimeled= millis();
    digitalWrite(15, !digitalRead(15));
  }
  if(millis() - oldtime >= 60000){
    oldtime= millis();
  
    // Ensure the connection to the MQTT server is alive (this will make the first
    // connection and automatically reconnect when disconnected).  See the MQTT_connect
    // function definition further below.
    MQTT_connect();

    float temp = bme.readTemperature();
    float hum = bme.readHumidity();
    float pressure = bme.readPressure() / 100.0F;
    float aqi = ENS160.getAQI();
    float tvoc = ENS160.getTVOC();
    float eco2 = ENS160.getECO2();

    // Now we can publish stuff!
    Serial.print(F("\nSending val "));
    Serial.print(temp);
    Serial.print(F(" to test feed..."));
    if (! temperaturereadings.publish(temp)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
    if (! humidityreadings.publish(hum)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
    if (! pressurereadings.publish(pressure)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
    if (! aqireadings.publish(aqi)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
    if (! tvocreadings.publish(tvoc)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
    if (! eco2readings.publish(eco2)) {
      Serial.println(F("Failed"));
    } else {
      Serial.println(F("OK!"));
    }
  }
  
  

}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3; // Only try a few times to reconnect
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
    retries--;
    if (retries == 0) {
      Serial.println("MQTT connection failed after retries.");
      return; // Give up and return. We will try again in next loop
    }
  }

  Serial.println("MQTT Connected!");
}

You have to create the topics below in the Adafruit.io website, as well as typing them exactly like below in the Arduino sketch above:

Adafruit_MQTT_Publish temperaturereadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperaturereadings");
Adafruit_MQTT_Publish humidityreadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidityreadings");
Adafruit_MQTT_Publish pressurereadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/pressurereadings");
Adafruit_MQTT_Publish aqireadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/aqireadings");
Adafruit_MQTT_Publish tvocreadings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tvocreadings");
Adafruit_MQTT_Publish eco2readings = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/eco2readings");

End result

I have downloaded and installed in my Android cellphone, an app called “MQTT Dash”. After configuring it with my Adafruit credentials, I was able to see something like the screen below.

MQTT Dash app showing sensor data

Such screen updates every 60 seconds with fresh information coming from the ESP32. Sensors are read and do not receive any special threatment, nor averaging and the likes. I made a full video showing how the system works, enjoy!.

Leave a Reply

Your email address will not be published. Required fields are marked *