Temperature and humidity tracker


Table Of Content

Ingredients

Hardware

  • WiFi NodeMCU
  • DHT11

Software

  • ArduinoIDE
  • InfluxDB

Arduino Libraries

  • ESP8266WiFi
  • ArduinoJson
  • InfluxDbClient
  • TM1637Display
  • DHT

APIs

  • OpenWeatherMap

Code

#include "secrets.h"

// Include WiFi library
#include <ESP8266WiFi.h>

// WiFi config
char ssid[] = SECRET_SSID; // network SSID
char pass[] = SECRET_PASS; // network password
WiFiClient networkClient;

// Add JSON support
#include <ArduinoJson.h>

// Add weather api (refer to https://openweathermap.org/current)
const char weather_server[] = "api.openweathermap.org";
const char weather_query[] = "GET /data/2.5/weather?lat=%s&lon=%s&units=metric&APPID=%s";
const char weather_message[] = "Outside: %f --- Inside: %f";
static unsigned long weather_api_time = -600000; // Used to time the API calls
static float h_api;
static float t_api;


// MASTER InfluxDB library
#include <InfluxDbClient.h>

// MASTER InfluxDB cfg
InfluxDBClient client_idb(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN);
Point pointDevice("device_status");
#define DB_DELAY 120000 //Write to DB every 2 min

// Include display library
#include <TM1637Display.h>
#define TM1637_CLK D1   // chip clock
#define TM1637_DIO D2   // chip digital I/O
#define DELAY 500   // delay between display updates
TM1637Display display(TM1637_CLK, TM1637_DIO);

// Set button pin
#define BUTTON D5
#define BUTTON_DEBOUNCE_DELAY 20

// Include DHT sensor libraries
#include <DHT.h>

// DHT sensor
#define DHTPIN D3
#define DHTTYPE DHT11

// Initialize DHT sensor
DHT dht = DHT(DHTPIN, DHTTYPE);

// Flag to show temp or humidity
static int show_temp = 0;
//  Variables to store temperature and humidity
static float h;
static float t;

void setup() {

  Serial.begin(115200);
  Serial.println(F("\n\nInit setup.\n"));


  dht.begin();
  Serial.println(F("DHT setup completed.\n"));

  // Set BUTTON pin as input with pull-up
  pinMode(BUTTON, INPUT_PULLUP);
  Serial.println(F("BUTTON setup completed.\n"));

  // Set wifi
  WiFi.mode(WIFI_STA);
  Serial.println(F("WIFI setup completed.\n"));

  // Set insecure connection to skip server certificate validation
  client_idb.setInsecure();

  Serial.println(F("\nSetup completed.\n"));
}

void loop() {

  // Used to time sensor reading
  static unsigned long time_temp = 0;

  // Save IP address
  String IP_local = "No connection";

  // Display brightness
  static unsigned long display_timer = 0;
  if (millis() - display_timer > 5000) {
    display.setBrightness(0x00);
  }

  //  Display updates timer
  static unsigned long time_monitor = 0;

  // DB Initialization flag
  int static init_db = 0;

  // DB write timing (skip first 120 seconds)
  static unsigned long time_db = 120000;


  if (isButtonPressed() == true) {   // button pressed
    // Set display to maximum brightness
    display.setBrightness(0x07);
    show_temp = !show_temp;
    display_timer =  millis();
  }
  if (millis() - time_temp > 2000) {
      h = dht.readHumidity();      // humidity percentage, range 20-80% (±5% accuracy)
      t = dht.readTemperature();   // temperature Celsius, range 0-50°C (±2°C accuracy)

      Serial.print(F("Humidity: "));
      Serial.print(h);
      Serial.print(F("%  Temperature: "));
      Serial.print(t);
      Serial.print(F("\n"));

      //  Set timer
      time_temp =  millis();
  }
  if (show_temp == 0) {
    if (millis() - time_monitor > DELAY) {
      uint8_t data[] = {
      SEG_B | SEG_C | SEG_F | SEG_E | SEG_G,           // H
      0x00,                                            // 0
      0x00,                                            // 0
      0x00                                             // 0
      };
      data[2] = display.encodeDigit(int(int(h / 10) % 10));
      data[3] = display.encodeDigit(int(int(h) % 10));
      display.setSegments(data);
      time_monitor =  millis();
    }
  }
  else {
    if (millis() - time_monitor > DELAY) {
      uint8_t data[] = {
      0x00,                                           // 0
      0x00,                                           // 0
      0x00,                                           // 0
      SEG_A | SEG_D | SEG_E | SEG_F                   // C
      };
      data[0] = display.encodeDigit(int(int(t / 10) % 10));
      data[1] = display.encodeDigit(int(int(t) % 10));
      display.setSegments(data);
      time_monitor =  millis();
    }
  }

  //  Connect to wifi if not connected
  IP_local = connectionToWiFi();

  getCurrentWeather();

  // Do TB things
  if (millis() - time_db > DB_DELAY && t > 0 && h > 0)
  {
    // Save data to DB
    check_influxdb();

    if (init_db == 0)
    { // set tags
      pointDevice.addTag("device", "ESP8266");
      pointDevice.addTag("SSID", WiFi.SSID());
      init_db = 1;
    }

    WriteMultiToDB(t, h);
    time_db = millis();
  }

}

String connectionToWiFi() {

  String IP;
  // connect to WiFi (if not already connected)
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print(F("Connecting to SSID: "));
    Serial.println(SECRET_SSID);

    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED) {
      // Signal something is wrong
      display.setBrightness(0x00);
      uint8_t data[] = {
      SEG_B | SEG_C | SEG_E | SEG_F | SEG_G,          // H
      SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,          // E
      SEG_D | SEG_E | SEG_F,                          // L
      SEG_A | SEG_B | SEG_E | SEG_F | SEG_G           // P
      };
      display.setSegments(data);
      delay(500);
    }
    Serial.println(F("\nConnected!"));

    printWifiStatus();

    IP = WiFi.localIP().toString();
    return IP;
  }
  else {
    IP = WiFi.localIP().toString();
    return IP;
  }
}

void printWifiStatus() {
  Serial.println(F("\n=== WiFi connection status ==="));

  // SSID
  Serial.print(F("SSID: "));
  Serial.println(WiFi.SSID());

  // signal strength
  Serial.print(F("Signal strength (RSSI): "));
  Serial.print(WiFi.RSSI());
  Serial.println(" dBm");

  // current IP
  Serial.print(F("IP Address: "));
  Serial.println(WiFi.localIP());

  // subnet mask
  Serial.print(F("Subnet mask: "));
  Serial.println(WiFi.subnetMask());

  // gateway
  Serial.print(F("Gateway IP: "));
  Serial.println(WiFi.gatewayIP());

  // DNS
  Serial.print(F("DNS IP: "));
  Serial.println(WiFi.dnsIP());

  Serial.println(F("==============================\n"));
}

boolean isButtonPressed() {
  static byte lastState = digitalRead(BUTTON);   // the previous reading from the input pin

  for (byte count = 0; count < BUTTON_DEBOUNCE_DELAY; count++) {
    if (digitalRead(BUTTON) == lastState) return false;
    delay(1);
  }

  lastState = !lastState;
  return lastState == HIGH ? false : true;
}

void check_influxdb() {
  // Check server connection
  if (client_idb.validateConnection()) {
    Serial.print(F("Connected to InfluxDB: "));
    Serial.println(client_idb.getServerUrl());
  } else {
    Serial.print(F("InfluxDB connection failed: "));
    Serial.println(client_idb.getLastErrorMessage());
  }
}

void WriteMultiToDB(float temp, float hum) {
  // Store measured value into point
  pointDevice.clearFields();
  pointDevice.addField("temperature", temp);
  pointDevice.addField("humidity", hum);
  pointDevice.addField("api_temperature", t_api);
  pointDevice.addField("api_humidity", h_api);
  pointDevice.addField("temperature_delta", temp - t_api);
  pointDevice.addField("humidity_delta", hum - h_api);
  Serial.print(F("Writing: "));
  Serial.println(pointDevice.toLineProtocol());
  if (!client_idb.writePoint(pointDevice)) {
    Serial.print(F("InfluxDB write failed: "));
    Serial.println(client_idb.getLastErrorMessage());
  }
}

void getCurrentWeather() {
  if (millis() - weather_api_time > 600000) {

    // call API for current weather
    if (networkClient.connect(weather_server, 80)) {
      char request[128];
      sprintf(request, weather_query, WEATHER_LATITUDE, WEATHER_LONGITUDE, WEATHER_API_KEY);
      networkClient.println(request);
      networkClient.println(F("Host: api.openweathermap.org"));
      networkClient.println(F("User-Agent: ArduinoWiFi/1.1"));
      networkClient.println(F("Connection: close"));
      networkClient.println();
    } else {
      Serial.println(F("Connection to api.openweathermap.org failed!\n"));
    }

    while (networkClient.connected() && !networkClient.available()) delay(1);   // wait for data
    String result;
    while (networkClient.connected() || networkClient.available()) {   // read data
      char c = networkClient.read();
      result = result + c;
    }

    networkClient.stop();   // end communication

    char jsonArray[result.length() + 1];
    result.toCharArray(jsonArray, sizeof(jsonArray));
    jsonArray[result.length() + 1] = '\0';
    StaticJsonDocument<1024> doc;
    DeserializationError error = deserializeJson(doc, jsonArray);

    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.c_str());
      return;
    }

    Serial.print(F("Location: "));
    Serial.println(doc["name"].as<String>());
    Serial.print(F("Country: "));
    Serial.println(doc["sys"]["country"].as<String>());
    Serial.print(F("Temperature (°C): "));
    Serial.println((float)doc["main"]["temp"]);
    t_api = (float)doc["main"]["temp"];
    Serial.print(F("Humidity (%): "));
    Serial.println((float)doc["main"]["humidity"]);
    h_api = (float)doc["main"]["humidity"];

    //  Set timer
    weather_api_time = millis();
  }
}

Results

influxdb-dashboard

nodemcu-running