Battery operated thermometer with connection to BLYNK
self-sufficient with battery operation and multi-wifi support
Components and supplies
1
WEMOS dual shield
1
Resistor 100k ohm
1
Battery, 3.7 V
1
Wemos battery shield
1
Wemos DS18B20 shield
1
Arduino UNO
1
Wemos D1 Mini
1
e-paper display 1.5
Tools and machines
1
Laser cutter (generic)
Apps and platforms
1
Arduino IDE
1
Blynk
Project description
Code
Sketch
arduino
1/* 2thermometer 3 by smi1100 - 08/08/2022 4 5PINS: 6 Display: 3.3(grey), GND(brown), DIN - D7(blue), CLK - D5(yellow), CS - D8(red), RST - D1(white), Busy - D6(purple) (because of DS18B20 Chip - D2) 7 WEMOS: connect D0 with RST -> connect after uploading the program 8 9WEMOS dual shield: 10 1 - base shield 1 -> WEMOS 11 2 - base shield 2 -> DS18B20 -> battery shield 12 13battery: 14 3.7 V 1.100 mAh - voltage between 3.2 and 4.2 V 15 16soldering: 17 100k ohm resistor between + and A0 on the battery shield 18 19library: 20 GxEPD2 from Zingg 21 22fonts: 23 https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts 24 25convert image: 26 http://javl.github.io/image2cpp/ - settings: 30x30, transparent, invert 27*/ 28 29// voltage measurement 30 31int volt_raw=0; 32float volt=0.0; 33float volt_percent=0; 34int volt_percent_width=0; 35float volt_min = 3.2; // adjust after replacing the battery 36float volt_max = 4.204; // adjust after replacing the battery 37float volt_critical = 3.76; // below this, measurement data are incorrect 38String Controller_Status; // Status could be "battery loading, battery operation, low battery" 39 40// EEPROM 41 42#include <EEPROM.h> 43float t_min = 30; 44float t_min_address = 0; 45float t_min_out; 46float t_max = 10; 47float t_max_address = 50; 48float t_max_out; 49 50// display 51 52#include <GxEPD2_BW.h> // library for b/w display 53GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D1*/ 5, /*BUSY=von D2(4) auf D6(12)*/ 12)); 54 55#include <Fonts/FreeMono12pt7b.h> // include fonts 56#include <Fonts/FreeMonoBold12pt7b.h> 57#include <Fonts/FreeMonoBold18pt7b.h> 58#include <Fonts/FreeMonoBold24pt7b.h> 59 60#include "imagedata.h" // data for the picture 61 62 63// Blynk 64 65#include <ESP8266WiFi.h> 66#include <BlynkSimpleEsp8266.h> 67 68char auth[] = "#########"; // WEMOS authentication BLYNK 69char* ssid[] = {"#########","#########","#########"}; // MultiWIFI - tries to connect one after the other 70char* pass[] = {"#########","#########","#########"}; 71 72String wlanname = ""; // connected WIFI -> sent to BLYNK 73 74 75// DS18B20 76 77#include <OneWire.h> 78#include <DallasTemperature.h> 79 80#define ONE_WIRE_BUS 4 //D2 PIN 81OneWire oneWire(ONE_WIRE_BUS); 82DallasTemperature sensor(&oneWire); 83 84float temperature; 85 86 87// Deep Sleep 88 89int deep_sleep_time = 300; // duration of deep sleep in sec. 90 91 92// ++++++++++++++++++++++++++++++++++++ SETUP ++++++++++++++++++++++++++++++++++++ 93 94void setup() 95{ 96 Serial.begin(115200); 97 98 // voltage measurement 99 100 pinMode(A0, INPUT); 101 102 // EEPROM 103 104 EEPROM.begin(512); 105 //EEPROM.put(t_min_address, t_min); // activate on the first run 106 //EEPROM.put(t_max_address, t_max); // activate on the first run 107 EEPROM.commit(); 108 109 // display 110 111 display.init(); // initialize display 112 display.setRotation(3); // rotate display 113 display.setTextColor(GxEPD_BLACK); // choose black colour 114 115 display.firstPage(); 116 do 117 { 118 display.fillScreen(GxEPD_WHITE); // fill background with white colour 119 120 display.setFont(&FreeMonoBold12pt7b); 121 display.setCursor(0, 132); display.print("Batt."); 122 123 display.setFont(&FreeMonoBold24pt7b); 124 display.setCursor(160, 65); display.print("C"); 125 display.fillCircle(155, 35, 5, GxEPD_BLACK); 126 127 display.drawRect(80, 115, 110, 25, GxEPD_BLACK); 128 } 129 while (display.nextPage()); 130 131 132 // Blynk 133 134 MultyWiFiBlynkBegin(); //instead Blynk.begin(auth, ssid, pass); 135 136 Serial.println("Deep Sleep activated"); Serial.println(""); 137 138 // DS18B20 139 140 sensor.begin(); 141 Serial.print("number of sensors: "); 142 Serial.println(sensor.getDeviceCount()); Serial.println(""); 143 144 // Deep Sleep 145 146 Serial.setTimeout(2000); //as long as the serial interface is not ready, do... (nothing) 147 while(!Serial) { } 148} 149 150 151void MultyWiFiBlynkBegin() 152{ 153 int ssid_count=0; 154 int ssid_mas_size = sizeof(ssid) / sizeof(ssid[0]); 155 do 156 { 157 Serial.println(""); 158 Serial.println("Trying to connect to wi-fi " + String(ssid[ssid_count])); 159 WiFi.begin(ssid[ssid_count], pass[ssid_count]); 160 int WiFi_timeout_count=0; 161 while (WiFi.status() != WL_CONNECTED && WiFi_timeout_count<50) { //waiting 10 sec 162 delay(200); 163 Serial.print("."); 164 ++WiFi_timeout_count; 165 } 166 if (WiFi.status() == WL_CONNECTED) 167 { 168 Serial.println(""); 169 Serial.println("Connected to wi-fi " + String(ssid[ssid_count])); 170 Serial.println(""); 171 Serial.println("Check connection to the Blynk server"); 172 Blynk.config(auth); 173 Blynk.connect(5000); //waiting 5 sec 174 wlanname = String(ssid[ssid_count]); 175 } 176 ++ssid_count; 177 } 178 while (!Blynk.connected() && ssid_count<ssid_mas_size); 179 if (!Blynk.connected() && ssid_count==ssid_mas_size) 180 { 181 Serial.println(""); 182 Serial.println("No connection to blynk, still try to connect to wi-fi " + String(ssid[ssid_count-1])); Serial.println(""); 183 wlanname = "offline"; 184 } 185 updateWLAN(wlanname); 186 Serial.println(""); 187 Blynk.virtualWrite(V3, wlanname); // send name of connection to BLYNK 188} 189 190void updateWLAN(String& str) 191{ 192 int16_t tbx, tby; // Die Variablen tbx, tby, tbw und tbh werden mit den Werten gefllt, die das partielle Fenster einnehmen wird. Die Abkrzung "tb" steht fr "text boundary" 193 uint16_t tbw, tbh; 194 uint16_t x = 0; // Die Variablen x und y sind der Eckpunkt unseres Ausgabefensters. Hier ist zu beachten, dass es nicht die linke obere Ecke ist, sondern die Grundlinie des Textes 195 uint16_t y = 185; 196 display.getTextBounds(wlanname, x, y, &tbx, &tby, &tbw, &tbh); // berechnet die Gre des Fensters 197 display.setFont(&FreeMonoBold12pt7b); 198 display.setTextColor(GxEPD_BLACK); 199 display.setPartialWindow(tbx, tby, tbw, tbh); 200 display.firstPage(); 201 do { 202 display.fillScreen(GxEPD_WHITE); 203 display.setCursor(x, y); 204 display.print(wlanname); 205 } 206 while (display.nextPage()); 207} 208 209// ++++++++++++++++++++++++++++++++++++ LOOP ++++++++++++++++++++++++++++++++++++ 210 211void loop() 212{ 213 Blynk.run(); 214 climateRoutine(); 215} 216 217void climateRoutine() 218{ 219 220// voltage measurement 221 222volt_raw = analogRead(A0); 223volt=volt_raw/1023.0*volt_max; 224volt_percent=((volt-volt_min)/(volt_max-volt_min)*100); 225 226Serial.print("sensor value: "); 227Serial.print(volt_raw); 228Serial.print(" | "); 229Serial.print("battery voltage: "); 230Serial.print(volt); 231Serial.print(" | "); 232Serial.print("battery voltage in %: "); 233Serial.println(volt_percent); 234Serial.println(""); 235Serial.println("calculation:"); Serial.println(""); 236Serial.print(volt); Serial.print(" - "); Serial.println(volt_min); 237Serial.print("------------ * 100 = "); Serial.print(volt_percent); Serial.println(" %"); 238Serial.print(volt_max); Serial.print(" - "); Serial.println(volt_min); Serial.println(""); 239 240// DS18B20 241 242sensor.requestTemperatures(); 243temperature = sensor.getTempCByIndex(0); 244Serial.print("temperature = "); Serial.print(temperature); Serial.println(" C "); 245 246// EEPROM 247 248EEPROM.get(t_min_address, t_min_out); 249Serial.print(" old temperature min = "); Serial.print(t_min_out); Serial.println(" C "); 250if (temperature < t_min_out) 251{ 252 t_min_out = temperature; 253 EEPROM.put(t_min_address, t_min_out); 254 Serial.print(" -> new temperature min = "); Serial.println(temperature); Serial.println(""); 255} 256else Serial.println(" -> NO new temperature min"); Serial.println(""); 257// EEPROM.end(); 258 259EEPROM.get(t_max_address, t_max_out); 260Serial.print(" old temperature max = "); Serial.print(t_max_out); Serial.println(" C "); 261if (temperature > t_max_out) 262{ 263 t_max_out = temperature; 264 EEPROM.put(t_max_address, t_max_out); 265 Serial.print(" -> new temperature max = "); Serial.println(temperature); Serial.println(""); 266} 267else Serial.println(" -> NO new temperature max"); Serial.println(""); 268EEPROM.end(); 269 270updateTemp(temperature); 271updateTemp(temperature); // twice, otherwise the display will not be correct at the beginning (cuts off the window) 272 273if (volt_percent < 20) 274{ 275 updateVoltage_alarm(); 276 updateVoltage_alarm(); 277} 278else 279{ 280 updateVoltage_percent(volt_percent); 281 updateVoltage_percent(volt_percent); 282} 283 284// Blynk 285 286if (volt < volt_critical) // dont transmit temperature data if voltage is lower than 3.76 Volt -> incorrect data 287{ 288 Controller_Status = "***** low battery *****"; 289 Blynk.virtualWrite(V0, temperature); 290 Blynk.virtualWrite(V6, t_min_out); 291 Blynk.virtualWrite(V7, t_max_out); 292} 293 294if (volt >= volt_critical) // && volt < volt_max) 295{ 296 Blynk.virtualWrite(V0, temperature); 297 Blynk.virtualWrite(V6, t_min_out); 298 Blynk.virtualWrite(V7, t_max_out); 299 Controller_Status = "operated by battery"; 300} 301 302if (volt >= volt_max) // dont transmit temperature data if voltage is higher than 4.2 Volt -> charging heats up the temperature sensor and leads to incorrect data 303{ 304 Controller_Status = "operated with the grid - battery loading"; 305} 306Serial.print("Controller Status = "); Serial.println(Controller_Status); Serial.println(""); 307Blynk.virtualWrite(V1, volt); 308Blynk.virtualWrite(V2, volt_percent); 309Blynk.virtualWrite(V4, deep_sleep_time/60); 310Blynk.virtualWrite(V5, Controller_Status); 311Serial.println("Daten an Blynk gesendet"); Serial.println(""); 312 313 314// display 315 316display.hibernate(); 317 318 319// Deep Sleep 320 321Serial.println("Initiate deep sleep"); Serial.println(""); 322ESP.deepSleep(deep_sleep_time*1000*1000); 323delay(100); 324} 325 326void updateTemp(float temperature) 327{ 328 char temp_string[] = {'0', '0', '\\0'}; // Es wird ein character-Array erzeugt, das mit 0 befllt wird 329 int16_t tbx, tby; // Die Variablen tbx, tby, tbw und tbh werden mit den Werten gefllt, die das partielle Fenster einnehmen wird. Die Abkrzung "tb" steht fr "text boundary" 330 uint16_t tbw, tbh; 331 332 dtostrf(temperature, 4, 1, temp_string); // Dann werden die bergebenen Sensordaten in das Array geschrieben. Dabei werden die Ziffern in char gewandelt. 333 // Die Funktion dtostrf() zum Konvertieren kann auch Nachkommastellen in das Array schreiben. 334 // temperature ist input (float), temp_string ist Output (char), 4 = Anzahl aller Stellen inkl. Komma, 0 Anzahl der Stellen nach dem Komma 335 uint16_t x = 20; // Die Variablen x und y sind der Eckpunkt unseres Ausgabefensters. Hier ist zu beachten, dass es nicht die linke obere Ecke ist, sondern die Grundlinie des Textes 336 uint16_t y = 65; 337 display.getTextBounds(temp_string, x, y, &tbx, &tby, &tbw, &tbh); // berechnet die Gre des Fensters 338 display.setFont(&FreeMonoBold24pt7b); 339 display.setTextColor(GxEPD_BLACK); 340 display.setPartialWindow(tbx, tby, tbw, tbh); 341 display.firstPage(); 342 do { 343 display.fillScreen(GxEPD_WHITE); 344 display.setCursor(x, y); 345 display.print(temp_string); 346 } 347 while (display.nextPage()); 348} 349 350 351void updateVoltage_percent(float volt_percent) 352{ 353 display.setPartialWindow(85, 120, 100, 15); 354 display.firstPage(); 355 do 356 { 357 display.fillRect(85, 120, volt_percent, 15, GxEPD_BLACK); 358 } 359 while (display.nextPage()); 360} 361 362 363void updateVoltage_alarm() 364{ 365 display.setPartialWindow(115, 112, 30, 30); 366 display.firstPage(); 367 do 368 { 369 display.drawBitmap(117, 112, IMAGE_DATA, 30, 30, GxEPD_BLACK); 370 } 371 while (display.nextPage()); 372} 373
Documentation
Box
Inkscape file
Box
Comments
Only logged in users can leave comments