Just my battery operated ESP8266 enviro sensor node with OTA update

thank you! It works now! :slight_smile:
I have also added to the code Uptime to check random reset

I have to figure out how to manage decimal, I don’t like too much! One is enough! :smiley:

my updated code to use use the Adafruit BME280 library.

  • a new addition is the tempChange notify section,

so that if the temp goes up/down by more than a set amount over the device period (12 mins in my case) then Blynk Notify tells you.

for me - this helps me to know when to open the doors & windows when the southerly change is coming through, or to close up the house when the sun is starting to make its radiation known…

hopefully it is of use to you too :slight_smile:

i think i will use it for Lux, humidity & air pressure changes too… i will see how it goes :sunny:

//#define BLYNK_PRINT Serial //this is the debugging for Blynk
//#define BLYNK_DEBUG        // Optional, this enables 'full' debugging detailed prints
#define debug 0 // this is the debugging tag - change to 0 to turn off debugging  serial prints

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>

#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#include <BH1750FVI.h>

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C

WiFiClient client;
BH1750FVI LightSensor;

const char* host = "esp8266"; // will be "esp8266.local/update" in web browser
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

SimpleTimer timer;

ADC_MODE(ADC_VCC);

IPAddress ip(192, 168, 0, 14); //check this!
IPAddress gateway(192, 168, 0, 1); //check this!
IPAddress subnet(255, 255, 255, 0); // check this!

int vcc = ESP.getVcc(); //readvdd33();

float humMin, humMax;
float temp, hum, pres, altitude;
float newTemp, oldTemp, tempChange;
float tempChangeSlider;
float tempChangeCoeff = 1;
float tempMin, tempMax, PreviousTempMin, PreviousTempMax;
double node3DewPoint;
int setProgramming, setProgrammingMode, resetMinMax;
int resetTemps;

long rssi = WiFi.RSSI();

// Time to sleep (in seconds):
const int sleepTimeS = 720; //this is 12 minutes (i.e. readings done 5 times per hour, 120 times per day)

const char* SSID = "xxx";
const char* pass = "yyy";

const char* serverThingspeak = "api.thingspeak.com"; //this is the Thingspeak address
String apiKeyThingspeak "abc"; // Channel 123

char authBlynk[] ="qwerty"; //insert token generated by Blynk

BLYNK_WRITE(V5)
{
  tempMin = param.asFloat();
  Blynk.virtualWrite(V5, tempMin);
}

BLYNK_WRITE(V6)
{
  tempMax = param.asFloat();
  Blynk.virtualWrite(V6, tempMax);
}


BLYNK_WRITE(V7)   // reset min/max temps
{
  resetMinMax = param.asInt();
  if (resetMinMax == 1) {
    resetTemps = 1;
    Blynk.virtualWrite(V7, 0);
  }
}

BLYNK_WRITE(V99)
{
  oldTemp = param.asFloat();
  Blynk.virtualWrite(V99, oldTemp);
}

BLYNK_WRITE(V13)   // sets temperature warning coefficent for Blynk Notify
{
  tempChangeSlider = param.asFloat();
  if (tempChangeSlider > 0)
  {
    tempChangeCoeff = tempChangeSlider / 5;
    Blynk.virtualWrite(V15, tempChangeCoeff);
  }
}

BLYNK_WRITE(V10)   // progamming mode - set this to prevent sleep
{
  setProgrammingMode = param.asInt();
  if (setProgrammingMode == 1) {
    setProgramming = 1;  // this stops esp.sleep so it can accept the OTA reprogramming
    Serial.println(F("set programing ACTIVATED"));
  }
  else if (setProgrammingMode == 0) {
    setProgramming = 0;  // this stops esp.sleep so it can accept the OTA reprogramming
    Serial.println(F("set programing INACTIVE"));
  }
}

void getSensorData()
{
  uint16_t lux = LightSensor.GetLightIntensity();// Get Lux value

  temp = bme.readTemperature();
  pres = bme.readPressure() / 100.0F;
  altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
  hum = bme.readHumidity();

  node3DewPoint = dewPointAccurate(temp, hum);

  if (debug == 1)
  {
    Serial.print("Temp: ");
    Serial.print(temp);
    Serial.println("'C");
    Serial.print("Humidity: ");
    Serial.print(hum);
    Serial.println("% RH");
    Serial.print("Pressure: ");
    Serial.print(pres);
    Serial.println(" hPa");
    Serial.print("Dew point: ");
    Serial.print(node3DewPoint);
    Serial.println("'C");
    Serial.print("Light: ");
    Serial.print(lux);
    Serial.println(" lux");
    Serial.println("-------------------------------------------");
  }

  Blynk.virtualWrite(V11, temp); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V9, hum); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V2, pres); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V8, node3DewPoint); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V19, vcc); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V18, rssi); // this sends the reading to the Blynk virtual pin
  Blynk.virtualWrite(V4, lux); // this sends the reading to the Blynk virtual pin

  newTemp = temp;

  if (debug == 1)
  {
    Serial.println("newTemp:");
    Serial.println(temp);
    Serial.println("current tempMin:");
    Serial.println(tempMin);
    Serial.println("current tempMax:");
    Serial.println(tempMax);
  }

  if (resetTemps == 1)
  {
    if (debug == 1)
    {
      Serial.println("resetting temps!");
    }
    tempMin = 50;
    tempMax = 0;
  }

  if (tempMin <= newTemp)
  {
    tempMin = tempMin;
    if (debug == 1)
    {
      Serial.println("no change to tempMin ");
    }
  }
  else if (tempMin > newTemp)
  {
    tempMin = newTemp;
    Blynk.virtualWrite(V5, tempMin);
    if (debug == 1)
    {
      Serial.println("tempMin updated");
    }
  }

  if (tempMax >= newTemp)
  {
    tempMax = tempMax;
    if (debug == 1)
    {
      Serial.println("no change to tempMax ");
    }
  }
  else if (tempMax < newTemp)
  {
    tempMax = newTemp;
    Blynk.virtualWrite(V6, tempMax);
    if (debug == 1)
    {
      Serial.println("tempMax updated");
    }
  }

  tempChange = newTemp - oldTemp;

  if (debug == 1)
  {
    Serial.print("newTemp:");
    Serial.println(newTemp);
    Serial.print("oldTemp:");
    Serial.println(oldTemp);
    Serial.print("tempChange:");
    Serial.println(tempChange);
    Serial.print("tempChangeCoeff:");
    Serial.println(tempChangeCoeff);
  }

  Blynk.virtualWrite(V14, tempChange);

  if ((tempChange > tempChangeCoeff) || (tempChange < -tempChangeCoeff))
  {
    Blynk.notify(String("BME280 Node06 -  temp change of ") + (tempChange) + ("detected in 12mins."));
  }

  oldTemp = temp;
  Blynk.virtualWrite(V99, oldTemp);

  if ((vcc < 3260) && (vcc > 3245))
  {
    Blynk.notify(String("NODE06 - Outside BME280 Sensor battery low: ") + vcc + ("mV"));
  }
  else if (vcc <= 3235)
  {
    Blynk.notify(String("NODE06 - Outside BME280 Sensor BATTERY CRITICAL:") + vcc + ("mV"));
  }

  if (client.connect(serverThingspeak, 80))
  {
    String postStr = apiKeyThingspeak;
    postStr += "&field1=";
    postStr += String(temp);
    postStr += "&field2=";
    postStr += String(hum);
    postStr += "&field3=";
    postStr += String(pres);
    postStr += "&field4=";
    postStr += String(rssi);
    postStr += "&field5=";
    postStr += String(vcc);
    //postStr += "&field6=";
    //postStr += String(lux);
    postStr += "&field7=";
    postStr += String(node3DewPoint);
    postStr += "\r\n\r\n";

    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + apiKeyThingspeak + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(postStr.length());
    client.print("\n\n");
    client.print(postStr);
  }
  if (debug == 1)
  {
    Serial.println(F("just thingspoke"));
  }
  delay(10);
  if (setProgramming == 0)
  {
    Blynk.virtualWrite(12, 0); // programming LED off
    delay(10);
    ESP.deepSleep(sleepTimeS * 1000000);
    delay(10);
  }
  else if (setProgramming == 1)
  {
    Blynk.virtualWrite(12, 1023); //programming LED on - device is NOT going to deepSleep
  }
}

void setup()
{
  {
    Serial.begin(115200);

    if (debug == 1)
    { Serial.print(F("File name: "));
      Serial.println(F(""));
      Serial.println(F("NODE06 - TPL Bug prototype BATTERY POWER - with Thingspeak & Blynk & Deep Sleep"));
      Serial.print(F("File name: "));
      Serial.println(__FILE__);
      Serial.println(F(""));
      Serial.print(F("ESP voltage: "));
      Serial.print(vcc);
      Serial.println(F("mV"));
      Serial.println(F(""));
      Serial.println(F("Where's Blynk??"));
    }

    WiFi.mode(WIFI_STA);
    WiFi.config(ip, gateway, subnet); // this sets the ESP IP configuration - AVOIDS using router DHCP to save battery
    WiFi.setOutputPower(0); // this is from conkerkh sets wifi to lowest power

    Blynk.begin(authBlynk, SSID, pass, IPAddress(192, 168, 0, 7)); //LOCAL server details
    // Blynk.begin(authBlynk, SSID, pass); use for CLOUD SERVER

    ArduinoOTA.setHostname("BME280_Node06");
    ArduinoOTA.onStart([]()
    {
      Serial.println("Start");
    });
    ArduinoOTA.onEnd([]()
    {
      Serial.println("\nEnd");
    });

    ArduinoOTA.onError([](ota_error_t error)
    {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });
    ArduinoOTA.begin();
    Serial.println("Ready - OTA Success!!!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    MDNS.begin(host);
    httpUpdater.setup(&httpServer);
    httpServer.begin();
    MDNS.addService("http", "tcp", 80);
    String ipaddress = WiFi.localIP().toString();
    String chipID = String(ESP.getChipId(), HEX);
    char charChipID[10];
    chipID.toCharArray(charChipID, sizeof(charChipID));
    char charipaddress[16];
    ipaddress.toCharArray(charipaddress, sizeof(charipaddress));
    Serial.printf("Now open http://%s.local/update in your browser or \n", host);
    Serial.printf("http://%s/update or http://%s.lan/update if you prefer.\n", charipaddress, charChipID);

    while (!Blynk.connect())
    {
      delay(500);
      Serial.print(F("."));
    }

    long rssi = WiFi.RSSI();

    if (debug == 1)
    {
      Serial.println(F(""));
      Serial.println(F("Found some WiFi!"));
      Serial.print(F("WiFi signal strength (RSSI): "));
      Serial.print(rssi);
      Serial.println(F(" dBm"));
      Serial.println("");
      Serial.println(F("Blynk started! "));
      Serial.println(F("------------"));
    }

    if (debug == 0)
    {
      Serial.println(F("***************************serial print debug is OFF***************************"));
    }

    Blynk.syncAll();

    LightSensor.begin();
    Wire.begin();
    LightSensor.SetAddress(Device_Address_L);//'L' = Address 0x5C ???
    LightSensor.SetMode(Continuous_H_resolution_Mode);
    timer.setInterval(60L * 1000L, getSensorData);

    while (!Serial)
    {
    } // Wait

    bme.begin();
    //    while (!bme.begin())
    //    {
    //      Serial.println("Could not find BME280 sensor!");
    //      delay(1000);
    //    }
  }
}

void loop()
{
  Blynk.run(); // Initiates Blynk
  timer.run(); // Initiates SimpleTimer
  ArduinoOTA.handle();
  httpServer.handleClient();
}

/*-----( Declare User-written Functions )-----*/
// dewPoint function NOAA
// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm
// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm
//
double dewPointAccurate (double celsius, double humidity)
{
  // (1) Saturation Vapor Pressure = ESGG(T)
  double RATIO = 373.15 / (273.15 + celsius);
  double RHS = -7.90298 * (RATIO - 1);
  RHS += 5.02808 * log10(RATIO);
  RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ;
  RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
  RHS += log10(1013.124); // NB = 1013 = absolute air pressure from BME280 sensor!!!!???????????????

  // factor -3 is to adjust units - Vapor Pressure SVP * humidity
  double VP = pow(10, RHS - 3) * humidity;

  // (2) DEWPOINT = F(Vapor Pressure)
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}
/* ==== END Functions ==== */
1 Like

in the last script
String apiKeyThingspeak “abc”; // Channel 123 change in
String apiKeyThingspeak = “abc”; // Channel 123

or it won’t compile :slight_smile:

BTW I have see a strange behavior with the code (the first example). The read function start after 60 seconds of power up! This literally eats the battery.

If you test code without Deep Sleep you’ll see some disconnections from Blynk that in console are reported like “timeout”

1 Like

yes, you should change to lowest possible number, thanks!

sorry, i wasn’t paying much attention to the console…

OK for anyone playing at home - they WERE fake batteries…

i have some Green Panasonic NCR18650PF batteries in it now and have hit 24,510 cycles alive with total runtime of 32,425,905mS which is nearly 9 hours ‘awake’ over probably six months.

3 Likes

also - i am using the finitespace library for BME280 nowadays:

2 Likes