Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
This is my fourth project with Arduino.
This device measures the temperature and is self-sufficient from a power supply. It uses a rechargeable battery with 1.100 mAh and 3.7V. With the deep sleep modus of the WEMOS mini it can sustain operation for a period of 10 days.
The WEMOS Mini, the DS 18B20 and the battery shield are attached on a dual shield. In order to be able to measure the voltage, it is necessary to attach a 100 kilo ohm resistor between the positive pole and the input a0 on the battery shield.
Pay attention to the poles of the battery and the battery shield. Sometimes they are swapped.
Please note. Each time a sketch is uploaded, the RST connection with D0 must be disconnected. After the upload of the sketch restore the connection, otherwise deep sleep mode is not possible.
The box is made of a 4 mm thick poplar plywood and cut with a laser cutter. The front and top of the box are not glued for maintenance.
The data are displayed on an e-paper display as well in the BLYNK app. If the battery voltage is low, a warning will be displayed on the e-paper display as well as in the Blynk app. The temperature and voltage are shown in diagrams in the app.
.) temperature
.) voltage
During the charging process, the transmission of the temperature is interrupted because the heat - generated during charging - falsifies the measured value. Even if the voltage is too low, the temperature is not transmitted because the sensor determines incorrect values in this state.
.) operated by battery
.) low battery
.) battery loading
The charging connector is on the bottom of the box.
Update - the BLYNK app listed in the project is no longer active. The server was shutdown on Dezember 2022. If you want to implement the project, you have to switch to the new version.
/*
thermometer
by smi1100 - 08/08/2022
PINS:
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)
WEMOS: connect D0 with RST -> connect after uploading the program
WEMOS dual shield:
1 - base shield 1 -> WEMOS
2 - base shield 2 -> DS18B20 -> battery shield
battery:
3.7 V 1.100 mAh - voltage between 3.2 and 4.2 V
soldering:
100k ohm resistor between + and A0 on the battery shield
library:
GxEPD2 from Zingg
fonts:
https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts
convert image:
http://javl.github.io/image2cpp/ - settings: 30x30, transparent, invert
*/
// voltage measurement
int volt_raw=0;
float volt=0.0;
float volt_percent=0;
int volt_percent_width=0;
float volt_min = 3.2; // adjust after replacing the battery
float volt_max = 4.204; // adjust after replacing the battery
float volt_critical = 3.76; // below this, measurement data are incorrect
String Controller_Status; // Status could be "battery loading, battery operation, low battery"
// EEPROM
#include <EEPROM.h>
float t_min = 30;
float t_min_address = 0;
float t_min_out;
float t_max = 10;
float t_max_address = 50;
float t_max_out;
// display
#include <GxEPD2_BW.h> // library for b/w display
GxEPD2_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));
#include <Fonts/FreeMono12pt7b.h> // include fonts
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include "imagedata.h" // data for the picture
// Blynk
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
char auth[] = "#########"; // WEMOS authentication BLYNK
char* ssid[] = {"#########","#########","#########"}; // MultiWIFI - tries to connect one after the other
char* pass[] = {"#########","#########","#########"};
String wlanname = ""; // connected WIFI -> sent to BLYNK
// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //D2 PIN
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensor(&oneWire);
float temperature;
// Deep Sleep
int deep_sleep_time = 300; // duration of deep sleep in sec.
// ++++++++++++++++++++++++++++++++++++ SETUP ++++++++++++++++++++++++++++++++++++
void setup()
{
Serial.begin(115200);
// voltage measurement
pinMode(A0, INPUT);
// EEPROM
EEPROM.begin(512);
//EEPROM.put(t_min_address, t_min); // activate on the first run
//EEPROM.put(t_max_address, t_max); // activate on the first run
EEPROM.commit();
// display
display.init(); // initialize display
display.setRotation(3); // rotate display
display.setTextColor(GxEPD_BLACK); // choose black colour
display.firstPage();
do
{
display.fillScreen(GxEPD_WHITE); // fill background with white colour
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(0, 132); display.print("Batt.");
display.setFont(&FreeMonoBold24pt7b);
display.setCursor(160, 65); display.print("C");
display.fillCircle(155, 35, 5, GxEPD_BLACK);
display.drawRect(80, 115, 110, 25, GxEPD_BLACK);
}
while (display.nextPage());
// Blynk
MultyWiFiBlynkBegin(); //instead Blynk.begin(auth, ssid, pass);
Serial.println("Deep Sleep activated"); Serial.println("");
// DS18B20
sensor.begin();
Serial.print("number of sensors: ");
Serial.println(sensor.getDeviceCount()); Serial.println("");
// Deep Sleep
Serial.setTimeout(2000); //as long as the serial interface is not ready, do... (nothing)
while(!Serial) { }
}
void MultyWiFiBlynkBegin()
{
int ssid_count=0;
int ssid_mas_size = sizeof(ssid) / sizeof(ssid[0]);
do
{
Serial.println("");
Serial.println("Trying to connect to wi-fi " + String(ssid[ssid_count]));
WiFi.begin(ssid[ssid_count], pass[ssid_count]);
int WiFi_timeout_count=0;
while (WiFi.status() != WL_CONNECTED && WiFi_timeout_count<50) { //waiting 10 sec
delay(200);
Serial.print(".");
++WiFi_timeout_count;
}
if (WiFi.status() == WL_CONNECTED)
{
Serial.println("");
Serial.println("Connected to wi-fi " + String(ssid[ssid_count]));
Serial.println("");
Serial.println("Check connection to the Blynk server");
Blynk.config(auth);
Blynk.connect(5000); //waiting 5 sec
wlanname = String(ssid[ssid_count]);
}
++ssid_count;
}
while (!Blynk.connected() && ssid_count<ssid_mas_size);
if (!Blynk.connected() && ssid_count==ssid_mas_size)
{
Serial.println("");
Serial.println("No connection to blynk, still try to connect to wi-fi " + String(ssid[ssid_count-1])); Serial.println("");
wlanname = "offline";
}
updateWLAN(wlanname);
Serial.println("");
Blynk.virtualWrite(V3, wlanname); // send name of connection to BLYNK
}
void updateWLAN(String& str)
{
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"
uint16_t tbw, tbh;
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
uint16_t y = 185;
display.getTextBounds(wlanname, x, y, &tbx, &tby, &tbw, &tbh); // berechnet die Gre des Fensters
display.setFont(&FreeMonoBold12pt7b);
display.setTextColor(GxEPD_BLACK);
display.setPartialWindow(tbx, tby, tbw, tbh);
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(wlanname);
}
while (display.nextPage());
}
// ++++++++++++++++++++++++++++++++++++ LOOP ++++++++++++++++++++++++++++++++++++
void loop()
{
Blynk.run();
climateRoutine();
}
void climateRoutine()
{
// voltage measurement
volt_raw = analogRead(A0);
volt=volt_raw/1023.0*volt_max;
volt_percent=((volt-volt_min)/(volt_max-volt_min)*100);
Serial.print("sensor value: ");
Serial.print(volt_raw);
Serial.print(" | ");
Serial.print("battery voltage: ");
Serial.print(volt);
Serial.print(" | ");
Serial.print("battery voltage in %: ");
Serial.println(volt_percent);
Serial.println("");
Serial.println("calculation:"); Serial.println("");
Serial.print(volt); Serial.print(" - "); Serial.println(volt_min);
Serial.print("------------ * 100 = "); Serial.print(volt_percent); Serial.println(" %");
Serial.print(volt_max); Serial.print(" - "); Serial.println(volt_min); Serial.println("");
// DS18B20
sensor.requestTemperatures();
temperature = sensor.getTempCByIndex(0);
Serial.print("temperature = "); Serial.print(temperature); Serial.println(" C ");
// EEPROM
EEPROM.get(t_min_address, t_min_out);
Serial.print(" old temperature min = "); Serial.print(t_min_out); Serial.println(" C ");
if (temperature < t_min_out)
{
t_min_out = temperature;
EEPROM.put(t_min_address, t_min_out);
Serial.print(" -> new temperature min = "); Serial.println(temperature); Serial.println("");
}
else Serial.println(" -> NO new temperature min"); Serial.println("");
// EEPROM.end();
EEPROM.get(t_max_address, t_max_out);
Serial.print(" old temperature max = "); Serial.print(t_max_out); Serial.println(" C ");
if (temperature > t_max_out)
{
t_max_out = temperature;
EEPROM.put(t_max_address, t_max_out);
Serial.print(" -> new temperature max = "); Serial.println(temperature); Serial.println("");
}
else Serial.println(" -> NO new temperature max"); Serial.println("");
EEPROM.end();
updateTemp(temperature);
updateTemp(temperature); // twice, otherwise the display will not be correct at the beginning (cuts off the window)
if (volt_percent < 20)
{
updateVoltage_alarm();
updateVoltage_alarm();
}
else
{
updateVoltage_percent(volt_percent);
updateVoltage_percent(volt_percent);
}
// Blynk
if (volt < volt_critical) // dont transmit temperature data if voltage is lower than 3.76 Volt -> incorrect data
{
Controller_Status = "***** low battery *****";
Blynk.virtualWrite(V0, temperature);
Blynk.virtualWrite(V6, t_min_out);
Blynk.virtualWrite(V7, t_max_out);
}
if (volt >= volt_critical) // && volt < volt_max)
{
Blynk.virtualWrite(V0, temperature);
Blynk.virtualWrite(V6, t_min_out);
Blynk.virtualWrite(V7, t_max_out);
Controller_Status = "operated by battery";
}
if (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
{
Controller_Status = "operated with the grid - battery loading";
}
Serial.print("Controller Status = "); Serial.println(Controller_Status); Serial.println("");
Blynk.virtualWrite(V1, volt);
Blynk.virtualWrite(V2, volt_percent);
Blynk.virtualWrite(V4, deep_sleep_time/60);
Blynk.virtualWrite(V5, Controller_Status);
Serial.println("Daten an Blynk gesendet"); Serial.println("");
// display
display.hibernate();
// Deep Sleep
Serial.println("Initiate deep sleep"); Serial.println("");
ESP.deepSleep(deep_sleep_time*1000*1000);
delay(100);
}
void updateTemp(float temperature)
{
char temp_string[] = {'0', '0', '\0'}; // Es wird ein character-Array erzeugt, das mit 0 befllt wird
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"
uint16_t tbw, tbh;
dtostrf(temperature, 4, 1, temp_string); // Dann werden die bergebenen Sensordaten in das Array geschrieben. Dabei werden die Ziffern in char gewandelt.
// Die Funktion dtostrf() zum Konvertieren kann auch Nachkommastellen in das Array schreiben.
// temperature ist input (float), temp_string ist Output (char), 4 = Anzahl aller Stellen inkl. Komma, 0 Anzahl der Stellen nach dem Komma
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
uint16_t y = 65;
display.getTextBounds(temp_string, x, y, &tbx, &tby, &tbw, &tbh); // berechnet die Gre des Fensters
display.setFont(&FreeMonoBold24pt7b);
display.setTextColor(GxEPD_BLACK);
display.setPartialWindow(tbx, tby, tbw, tbh);
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(temp_string);
}
while (display.nextPage());
}
void updateVoltage_percent(float volt_percent)
{
display.setPartialWindow(85, 120, 100, 15);
display.firstPage();
do
{
display.fillRect(85, 120, volt_percent, 15, GxEPD_BLACK);
}
while (display.nextPage());
}
void updateVoltage_alarm()
{
display.setPartialWindow(115, 112, 30, 30);
display.firstPage();
do
{
display.drawBitmap(117, 112, IMAGE_DATA, 30, 30, GxEPD_BLACK);
}
while (display.nextPage());
}
Comments