Stație meteo folosind un ESP32 LilyGo T5 cu ePaper
În proiectul de azi afișez date meteo culese de pe un site specializat (https://www.meteoromania.ro/), cum ar fi temperatura actuală, umiditatea sau alte informații meteorologice, și pentru asta am folosit capacitatea ESP32 de a face cereri HTTPS către serverul site-ului pentru a obține aceste date. Pe lângă asta am conectat dispozitivul și la serverul meu MQTT configurat în Home Asistant, și afișez data și ora de la un server NTP. Iată pașii de bază pentru a realiza aceste configurări în cadrul proiectului:
- Adăugarea conectivității WiFi la ESP32: Asigură-te că ESP32 LilyGo T5 este configurat pentru a se conecta la rețeaua WiFi disponibilă. Poți folosi biblioteca WiFi pentru a facilita procesul de configurare a rețelei WiFi.
- Realizarea cererilor HTTPS: Folosește biblioteca ESP32 ArduinoHttpClient pentru a face cereri HTTPS către serverul site-ului de unde dorești să preiei datele meteo. În mod tipic, vei face o cerere GET la un endpoint care returnează datele într-un format ușor de parsat, cum ar fi JSON sau XML , iar în cazul acesta avem datele în format JSON.
- Folosirea unei biblioteci HTTPS: În loc să folosești biblioteca standard HTTPClient, care este destinată cererilor HTTP nesecurizate, va trebui să utilizezi o bibliotecă care să permită cereri HTTPS. Pentru ESP32, poți folosi biblioteca ArduinoHttpClient, care suportă cereri HTTPS prin intermediul bibliotecii BearSSL.
- Configurarea cererii HTTPS: Veți trebui să specificați adresa URL a serverului meteo și să configurați cererea HTTPS pentru a face o cerere GET la acea adresă.
- Gestionarea certificatului SSL/TLS: Pentru a valida certificatul SSL/TLS al serverului meteo și pentru a asigura o conexiune securizată, va trebui să furnizezi bibliotecii SSL/TLS a ESP32-ului un set de certificate de încredere configurat în aplicație.Obținerea certificatului se poate face urmând pașii din imaginile de mai jos , eu am folosit browser-ul Opera, și după încărcarea paginii se dă click pe lăcățel:
Apoi click pe „Certificat is valid”:
Și apoi se exportă certificatul și se poate folosi:
Pentru a accesa în mod securizat website-ul,
vei avea nevoie de acest certificat SSL/TLS care să permită ESP32-ului tău
să stabilească o conexiune sigură cu serverul site-ului.
- Parsarea datelor: După ce primești răspunsul de la cererea HTTPS, vei trebui să parsezi datele JSON (cu lib-ul ArduinoJson) pentru a extrage informațiile relevante, cum ar fi temperatura, umiditatea sau prognoza.
- Afișarea datelor pe display-ul ePaper: După ce ai extras informațiile dorite, le poți afișa pe display-ul ePaper în mod similar cu afișarea datelor de la senzorii locali.
- Actualizarea periodică a datelor: Pentru a menține informațiile actualizate, poți programa ESP32 să facă cereri HTTPS la intervale regulate pentru a actualiza datele meteo.
Conexiune la serverul MQTT pentru a citi datele de temperatură:
- Instalarea bibliotecilor MQTT: Asigură-te că ai instalat biblioteca MQTT pentru Arduino. Poți folosi, de exemplu, biblioteca
PubSubClient
. - Conexiunea la serverul MQTT: Configură ESP32 pentru a se conecta la serverul MQTT și pentru a se abona la subiectul care trimite datele de temperatură.
- Citirea datelor de temperatură: După ce te-ai abonat la subiectul corespunzător, în cazul meu am avut deja configurat un senzor de temperatură dintr-un proiect anterior, poți citi datele de temperatură atunci când sunt publicate pe acest subiect.
Afișare orei și datei
Pentru a afișa data și ora folosind un server NTP (Network Time Protocol) pe ESP32 LilyGo T5, poți urma acești pași:
- Inițializarea și configurarea clientului NTP: În cod am apelat funcția configTime și am configurat pentru a se conecta la un server NTP. Eu am specifica un server NTP public, cum ar fi
pool.ntp.org
. - Obținerea datei și orei de la serverul NTP: Folosind metoda
getLocalTime()
pentru a obține data și ora curentă de la serverul NTP. - Afișarea datei și orei: Afișează data și ora obținute pe display-ul ePaper sau pe consola serială, după cum dorești.
Weather station
QR code
Pe lângă ce am configurat mai sus m-am jucat și cu o bibliotecă care generează QR code-uri. QR codul afișat referă website-ul https://www.meteoromania.ro/ .
Componente
Schema electronică/sistem
Codul de configurare și aplicația
// According to the board, cancel the corresponding macro definition | |
#define LILYGO_T5_V213 | |
// #define LILYGO_T5_V22 | |
// #define LILYGO_T5_V24 | |
// #define LILYGO_T5_V28 | |
// #define LILYGO_T5_V102 | |
// #define LILYGO_T5_V266 | |
// #define LILYGO_EPD_DISPLAY_102 | |
// #define LILYGO_EPD_DISPLAY_154 | |
#include <boards.h> | |
#define EINKDISPLAY | |
#include <GxEPD.h> | |
#if defined(LILYGO_T5_V102) || defined(LILYGO_EPD_DISPLAY_102) | |
#include <GxGDGDEW0102T4/GxGDGDEW0102T4.h> //1.02" b/w | |
#elif defined(LILYGO_T5_V266) | |
#include <GxDEPG0266BN/GxDEPG0266BN.h> // 2.66" b/w form DKE GROUP | |
#elif defined(LILYGO_T5_V213) | |
#include <GxDEPG0213BN/GxDEPG0213BN.h> // 2.13" b/w form DKE GROUP | |
// #include <GxGDE0213B1.h> | |
#else | |
// #include <GxGDGDEW0102T4/GxGDGDEW0102T4.h> //1.02" b/w | |
// #include <GxGDEW0154Z04/GxGDEW0154Z04.h> // 1.54" b/w/r 200x200 | |
// #include <GxGDEW0154Z17/GxGDEW0154Z17.h> // 1.54" b/w/r 152x152 | |
// #include <GxGDEH0154D67/GxGDEH0154D67.h> // 1.54" b/w | |
// #include <GxDEPG0150BN/GxDEPG0150BN.h> // 1.51" b/w form DKE GROUP | |
// #include <GxDEPG0266BN/GxDEPG0266BN.h> // 2.66" b/w form DKE GROUP | |
// #include <GxDEPG0290R/GxDEPG0290R.h> // 2.9" b/w/r form DKE GROUP | |
// #include <GxDEPG0290B/GxDEPG0290B.h> // 2.9" b/w form DKE GROUP | |
// #include <GxGDEW029Z10/GxGDEW029Z10.h> // 2.9" b/w/r form GoodDisplay | |
// #include <GxGDEW0213Z16/GxGDEW0213Z16.h> // 2.13" b/w/r form GoodDisplay | |
// #include <GxGDE0213B1/GxGDE0213B1.h> // 2.13" b/w old panel , form GoodDisplay | |
// #include <GxGDEH0213B72/GxGDEH0213B72.h> // 2.13" b/w old panel , form GoodDisplay | |
// #include <GxGDEH0213B73/GxGDEH0213B73.h> // 2.13" b/w old panel , form GoodDisplay | |
// #include <GxGDEM0213B74/GxGDEM0213B74.h> // 2.13" b/w form GoodDisplay 4-color | |
// #include <GxGDEW0213M21/GxGDEW0213M21.h> // 2.13" b/w Ultra wide temperature , form GoodDisplay | |
// #include <GxDEPG0213BN/GxDEPG0213BN.h> // 2.13" b/w form DKE GROUP | |
// #include <GxGDEW027W3/GxGDEW027W3.h> // 2.7" b/w form GoodDisplay | |
// #include <GxGDEW027C44/GxGDEW027C44.h> // 2.7" b/w/r form GoodDisplay | |
// #include <GxGDEH029A1/GxGDEH029A1.h> // 2.9" b/w form GoodDisplay | |
// #include <GxDEPG0750BN/GxDEPG0750BN.h> // 7.5" b/w form DKE GROUP | |
#endif | |
#include GxEPD_BitmapExamples | |
// FreeFonts from Adafruit_GFX | |
#include <Fonts/FreeMono9pt7b.h> | |
// #include <Fonts/Tiny3x3a2pt7b.h> | |
// #include <Fonts/FreeMonoBold9pt7b.h> | |
// #include <Fonts/FreeMonoBold12pt7b.h> | |
// #include <Fonts/FreeMonoBold18pt7b.h> | |
#include <Fonts/Picopixel.h> | |
#include <GxIO/GxIO_SPI/GxIO_SPI.h> | |
#include <GxIO/GxIO.h> | |
#include <qrcode.h> | |
#include <Wifi.h> | |
#include <HTTPClient.h> | |
#include <PubSubClient.h> | |
#include <Adafruit_INA219.h> | |
#include <ArduinoJson.h> | |
#include <Time.h> | |
#include <ESP32Time.h> | |
#define SERIAL_DEBUG_OFF | |
#define SERIAL_TIME_DATE_OFF | |
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ | |
#define TIME_TO_SLEEP 60 /* Time ESP32 will go to sleep (in seconds) */ | |
#define SIBIU 72 | |
#define TG_MURES 39 | |
#define INTORSURA_BUZAULUI 72 | |
#define DEFAULT_CITY_CODE 70 | |
#define CITY_CODE SIBIU | |
GxIO_Class io(SPI, EPD_CS, EPD_DC, EPD_RSET); | |
GxEPD_Class display(io, EPD_RSET, EPD_BUSY); | |
QRcode qrcode(&display); | |
void callback(char *topic, byte *payload, unsigned int length); | |
void printPanel(); | |
String printLocalTime(); | |
void printBatStatus(float battery_proc); | |
void printHeader(); | |
int getWifiStrenght(); | |
void drawWifiStrenght(int bars); | |
void batteryRead(void); | |
void setup_clock(); | |
String CheckString(String name, String str); | |
void SecureClientRead(); | |
/* Put your SSID & Password */ | |
const char *ssid = "SSID"; // Enter SSID here | |
const char *password = "password"; // Enter Password here | |
const char *ntpServer = "pool.ntp.org"; | |
const long gmtOffset_sec = 3600; | |
const int daylightOffset_sec = 3600; | |
String wifi_networks; | |
struct tm timeinfo; | |
// MQTT Broker | |
const char *mqtt_broker = "192.168.x.x"; | |
const char *topic_general = "emqx/esp32"; | |
const char *topic_temperatura = "workgroup/c4ca4238a0b923820dcc509a6f75849b/air/temperature"; | |
const char *mqtt_username = "mqtt_user"; | |
const char *mqtt_password = "mqtt_pass"; | |
const int mqtt_port = 1883; | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
char mesage_mqtt[200]; | |
float busvoltage_f; | |
String busvoltage_s; | |
Adafruit_INA219 ina219; | |
ESP32Time rtc(3600); // offset in seconds GMT+1 | |
wl_status_t wifi_connection; | |
String weather_server = "https://www.meteoromania.ro/wp-json/meteoapi/v2/starea-vremii"; | |
HTTPClient http; | |
const char *test_root_ca = "-----BEGIN CERTIFICATE-----\n" | |
" your cetificate here \n" | |
"-----END CERTIFICATE-----\n"; | |
String data_meteo; | |
String temperatura_locala; | |
String temp_int; | |
String presiunea_locala; | |
String viteza_vantului_locala; | |
String nebulozitate; | |
String umezeala; | |
String fenomene_precippitatii; | |
String zapada; | |
String actualizat; | |
String oras; | |
int page = 0; | |
String page_str; | |
const String configured_city_str = "SIBIU"; | |
int city_code_cfg = CITY_CODE; | |
unsigned long ClockSec = 0; | |
unsigned long Clock30Sec = 0; | |
unsigned long Clock1Sec = 0; | |
String CheckString(String name, String str) | |
{ | |
if ((str == "null") || (str.isEmpty() == true)) | |
{ | |
return "NA"; | |
} | |
else | |
{ | |
return name; | |
} | |
} | |
void SecureClientRead() | |
{ | |
WiFiClientSecure *clientSec = new WiFiClientSecure; | |
if (clientSec) | |
{ | |
clientSec->setCACert(test_root_ca); | |
{ | |
// Add a scoping block for HTTPClient https to make sure it is destroyed before WiFiClientSecure *client is | |
HTTPClient https; | |
https.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); | |
Serial.print("[HTTPS] begin...\n"); | |
if (https.begin(*clientSec, weather_server)) | |
{ // HTTPS | |
Serial.print("[HTTPS] GET...\n"); | |
// start connection and send HTTP header | |
int httpCode = https.GET(); | |
// httpCode will be negative on error | |
if (httpCode > 0) | |
{ | |
// HTTP header has been send and Server response header has been handled | |
Serial.printf("[HTTPS] GET... code: %d\n", httpCode); | |
// file found at server | |
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) | |
{ | |
#ifdef SERIAL_DEBUG_ON | |
String payload = https.getString(); | |
Serial.println(payload); | |
#endif | |
// Parse response | |
DynamicJsonDocument doc(65000); | |
DynamicJsonDocument doc_city(2000); | |
deserializeJson(doc, https.getStream()); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println(doc["features"][CITY_CODE].as<String>()); | |
#endif | |
if (city_code_cfg == 0) | |
{ | |
for (int i = 0; i < 161; i++) | |
{ | |
doc_city = doc["features"][i]; | |
deserializeJson(doc_city, doc["features"][i].as<String>()); | |
oras = doc_city["properties"]["nume"].as<String>(); | |
if (oras == configured_city_str) | |
{ | |
city_code_cfg = i; | |
#ifdef SERIAL_DEBUG_ON | |
Serial.printf("\nCity Code CFG: %d\n", city_code_cfg); | |
#endif | |
} | |
} | |
} | |
else | |
{ | |
doc_city = doc["features"][city_code_cfg]; | |
deserializeJson(doc_city, doc["features"][city_code_cfg].as<String>()); | |
// Read values | |
data_meteo = doc["date"].as<String>(); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println(doc["features"][city_code_cfg].as<String>()); | |
Serial.println(doc_city["properties"]["tempe"].as<String>()); | |
Serial.println(doc["date"].as<String>()); | |
#endif | |
oras = doc_city["properties"]["nume"].as<String>(); | |
temperatura_locala = doc_city["properties"]["tempe"].as<String>(); | |
presiunea_locala = doc_city["properties"]["presiunetext"].as<String>(); | |
viteza_vantului_locala = doc_city["properties"]["vant"].as<String>(); | |
nebulozitate = doc_city["properties"]["nebulozitate"].as<String>(); | |
umezeala = doc_city["properties"]["umezeala"].as<String>(); | |
fenomene_precippitatii = doc_city["properties"]["fenomen_e"].as<String>(); | |
zapada = doc_city["properties"]["zapada"].as<String>(); | |
actualizat = doc_city["properties"]["actualizat"].as<String>(); | |
} | |
} | |
} | |
else | |
{ | |
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str()); | |
} | |
https.end(); | |
} | |
else | |
{ | |
Serial.printf("[HTTPS] Unable to connect\n"); | |
} | |
// End extra scoping block | |
} | |
delete clientSec; | |
} | |
else | |
{ | |
Serial.println("Unable to create client"); | |
} | |
} | |
wl_status_t wifi_connect() | |
{ | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println("Connecting"); | |
#endif | |
while (WiFi.status() != WL_CONNECTED) | |
{ | |
delay(500); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.print("."); | |
#endif | |
} | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println(""); | |
Serial.print("Connected to WiFi network with IP Address: "); | |
Serial.println(WiFi.localIP()); | |
#endif | |
WiFi.setAutoReconnect(true); | |
WiFi.persistent(true); | |
return WiFi.status(); | |
} | |
void setup(void) | |
{ | |
#ifdef SERIAL_DEBUG_ON | |
Serial.begin(115200); | |
Serial.println(); | |
Serial.println("setup"); | |
#endif | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println("Connecting"); | |
#endif | |
while (WiFi.status() != WL_CONNECTED) | |
{ | |
delay(500); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.print("."); | |
#endif | |
} | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println(""); | |
Serial.print("Connected to WiFi network with IP Address: "); | |
Serial.println(WiFi.localIP()); | |
#endif | |
WiFi.setAutoReconnect(true); | |
WiFi.persistent(true); | |
setup_clock(); | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println(printLocalTime()); | |
#endif | |
#if defined(LILYGO_EPD_DISPLAY_102) | |
pinMode(EPD_POWER_ENABLE, OUTPUT); | |
digitalWrite(EPD_POWER_ENABLE, HIGH); | |
#endif /*LILYGO_EPD_DISPLAY_102*/ | |
#if defined(LILYGO_T5_V102) | |
pinMode(POWER_ENABLE, OUTPUT); | |
digitalWrite(POWER_ENABLE, HIGH); | |
#endif /*LILYGO_T5_V102*/ | |
SPI.begin(EPD_SCLK, EPD_MISO, EPD_MOSI); | |
display.init(); // enable diagnostic output on Serial | |
#ifdef SERIAL_DEBUG_ON | |
Serial.println("setup done"); | |
#endif | |
printPanel(); | |
qrcode.init(255, 122); | |
display.setCursor(2, 60); | |
qrcode.debug(); | |
// connecting to a mqtt broker | |
client.setServer(mqtt_broker, mqtt_port); | |
client.setCallback(callback); | |
while (!client.connected()) | |
{ | |
String client_id = "esp32-client-"; | |
client_id += String(WiFi.macAddress()); | |
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str()); | |
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) | |
{ | |
Serial.println("Public EMQX MQTT broker connected"); | |
} | |
else | |
{ | |
Serial.print("failed with state "); | |
Serial.print(client.state()); | |
delay(2000); | |
} | |
} | |
// Publish and subscribe | |
client.publish(topic_general, "Hi, I'm ESP32 ^^"); | |
client.subscribe(topic_general); | |
client.subscribe(topic_temperatura); | |
display.update(); | |
} | |
void loop() | |
{ | |
display.setRotation(1); | |
display.fillScreen(GxEPD_WHITE); | |
display.setTextColor(GxEPD_BLACK); | |
display.setFont(&FreeMono9pt7b); | |
display.setCursor(2, 20); | |
display.println(printLocalTime().c_str()); | |
if (millis() - ClockSec >= 500) | |
{ // 500 milisec = 1/2 sec | |
display.updateWindow(0, 250, 450, 40, true); // update clock window | |
// update 500ms clock | |
ClockSec = millis(); | |
} | |
display.setCursor(2, 40); | |
display.setCursor(110, 20); | |
if (WiFi.status() == WL_CONNECTED) | |
{ | |
int bars = getWifiStrenght(); | |
display.printf("%s(%d)", WiFi.SSID().c_str(), getWifiStrenght()); | |
drawWifiStrenght(bars); | |
client.loop(); | |
if (millis() - Clock30Sec >= 30000) | |
{ // 30000 milisec = 30 sec | |
SecureClientRead(); | |
// update clock variable | |
Clock30Sec = millis(); | |
} | |
} | |
else | |
{ | |
display.println("Not Connected"); | |
} | |
printPanel(); | |
/*Title */ | |
display.setFont(&FreeMono9pt7b); | |
display.setCursor(2, 40); | |
display.println(&timeinfo, "%d-%b-%Y"); | |
display.println("T ext " + temperatura_locala + "C"); | |
display.setCursor(2, 73); | |
display.println("T int " + temp_int.substring(1,6)+"C"); | |
display.setCursor(2, 88); | |
display.println("Hum "+ umezeala+ "%"); | |
int virgula = viteza_vantului_locala.indexOf(','); | |
String doar_viteza = viteza_vantului_locala.substring(0, virgula); | |
display.setCursor(2, 103); | |
display.println("Wind " + doar_viteza); | |
/* Content*/ | |
display.setCursor(2, 60); | |
// create qrcode | |
qrcode.create("https://www.meteoromania.ro/vremea/starea-vremii-romania/"); | |
/* Footer*/ | |
display.setFont(&FreeMono9pt7b); | |
display.setCursor(2, 123); | |
display.print(""); | |
int virgula_pres = presiunea_locala.indexOf(','); | |
String doar_presiunea = presiunea_locala.substring(0, virgula_pres); | |
display.print("Atm " + doar_presiunea); | |
if (millis() - Clock1Sec >= 1000) | |
{ | |
// display.update(); | |
display.updateWindow(100, 6, 170, 20, true); // update wifi name | |
display.updateWindow(0, 6, 250, 40, true); // update date window | |
display.updateWindow(0, 45, 250, 65, true); // update content window | |
display.updateWindow(0, 108, 250, 20, true); // update footer | |
// Actualizăm momentul ultimului apel | |
Clock1Sec = millis(); | |
} | |
#ifdef INA219_CHECK | |
// Initialize the INA219. | |
// By default the initialization will use the largest range (32V, 2A). However | |
// you can call a setCalibration function to change this range (see comments). | |
if (!ina219.begin()) | |
{ | |
Serial.println("Failed to find INA219 chip"); | |
while (1) | |
{ | |
delay(10); | |
} | |
} | |
else | |
{ | |
// display.updateWindow(230, 6, 20, 20, false); | |
} | |
#endif | |
} | |
/*----------------------------------------------------*/ | |
void printPanel() | |
{ | |
printHeader(); | |
/* x y width height */ | |
/* Title*/ | |
display.drawRect(0, 25, 150, 20, GxEPD_BLACK); // clock | |
/*Content*/ | |
display.drawRect(0, 45, 150, 65, GxEPD_BLACK); // content window which contain | |
/*footer*/ | |
display.drawRect(0, 108, 150, 20, GxEPD_BLACK); // footer panel | |
} | |
void printHeader() | |
{ | |
/* x y width height */ | |
display.drawRect(0, 6, 100, 20, GxEPD_BLACK); // date | |
display.drawRect(100, 6, 170, 20, GxEPD_BLACK); // wifi name | |
display.drawRect(230, 6, 20, 20, GxEPD_BLACK); // battery panel | |
printBatStatus(busvoltage_f / 6.0 * 100.0); | |
} | |
void printBatStatus(float battery_proc) | |
{ | |
int number_of_lines_to_draw = (int)round((battery_proc / 100.0 * 12.0)); | |
#ifdef SERIAL_DEBUG_DISPLAY_ON | |
Serial.printf("Battery procentage: %f\n", battery_proc); | |
Serial.printf("Nr de linii: %d", number_of_lines_to_draw); | |
#endif | |
if (number_of_lines_to_draw > 14) | |
{ | |
number_of_lines_to_draw = 14; | |
} | |
/* Draw empty battery*/ | |
/* x y width height */ | |
display.drawRect(235, 10, 10, 14, GxEPD_BLACK); | |
display.drawFastHLine(238, 8, 4, GxEPD_BLACK); | |
display.drawFastHLine(238, 9, 4, GxEPD_BLACK); | |
/* Fill battery based on battery_proc parameter */ | |
for (int i = 0; i < number_of_lines_to_draw; i++) | |
{ | |
display.drawFastHLine(235, 22 - i, 10, GxEPD_BLACK); | |
} | |
if (number_of_lines_to_draw < 3) | |
{ | |
display.drawLine(230, 6, 250, 26, GxEPD_BLACK); | |
} | |
else | |
{ | |
display.setCursor(236, 20); | |
display.setFont(&Picopixel); | |
display.setTextColor(GxEPD_WHITE); | |
display.printf("%1.1f", busvoltage_f); | |
} | |
display.setTextColor(GxEPD_BLACK); | |
} | |
void drawWifiStrenght(int bars) | |
{ | |
/* x y width height */ | |
for (int i = 1; i <= bars; i++) | |
{ | |
if (i == 5) | |
{ | |
display.fillRect(204 + (i * 4), 26 - (i * 4) + 2, 3, (i * 4) - 5, GxEPD_BLACK); | |
#ifdef SERIAL_DEBUG_DISPLAY_ON | |
Serial.printf("\nHeight max: %d", (i * 4) - 5); | |
#endif | |
} | |
else | |
{ | |
display.fillRect(204 + (i * 4), 26 - (i * 4), 3, (i * 4) - 3, GxEPD_BLACK); | |
#ifdef SERIAL_DEBUG_DISPLAY_ON | |
Serial.printf("\nHeight: %d", (i * 4) - 3); | |
#endif | |
} | |
} | |
} | |
String printLocalTime() | |
{ | |
if (!getLocalTime(&timeinfo)) | |
{ | |
#ifdef SERIAL_TIME_DATE_ON | |
Serial.println("Failed to obtain time"); | |
#endif | |
return String("NC"); | |
} | |
#ifdef SERIAL_TIME_DATE_ON | |
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); | |
Serial.print("Day of week: "); | |
Serial.println(&timeinfo, "%A"); | |
Serial.print("Month: "); | |
Serial.println(&timeinfo, "%B"); | |
Serial.print("Day of Month: "); | |
Serial.println(&timeinfo, "%d"); | |
Serial.print("Year: "); | |
Serial.println(&timeinfo, "%Y"); | |
Serial.print("Hour: "); | |
Serial.println(&timeinfo, "%H"); | |
Serial.print("Hour (12 hour format): "); | |
Serial.println(&timeinfo, "%I"); | |
Serial.print("Minute: "); | |
Serial.println(&timeinfo, "%M"); | |
Serial.print("Second: "); | |
Serial.println(&timeinfo, "%S"); | |
Serial.println("Time variables"); | |
char timeHour[3]; | |
char timeHMS[12]; | |
strftime(timeHour, 3, "%H", &timeinfo); | |
strftime(timeHMS, 11, "%H:%M:%S", &timeinfo); | |
Serial.println(timeHour); | |
char timeWeekDay[10]; | |
strftime(timeWeekDay, 10, "%A", &timeinfo); | |
Serial.println(timeWeekDay); | |
Serial.println(); | |
#endif | |
char timeDate[36]; | |
strftime(timeDate, 36, "%H:%M:%S", &timeinfo); | |
return String(timeDate); | |
} | |
int getWifiStrenght() | |
{ | |
int bars; | |
int RSSI_strgh = 0; | |
// simple if then to set the number of bars | |
RSSI_strgh = WiFi.RSSI(); | |
if (RSSI_strgh > -55) | |
{ | |
bars = 5; | |
} | |
else if ((RSSI_strgh < -55) && (RSSI_strgh > -65)) | |
{ | |
bars = 4; | |
} | |
else if ((RSSI_strgh < -65) && (RSSI_strgh > -70)) | |
{ | |
bars = 3; | |
} | |
else if ((RSSI_strgh < -70) && (RSSI_strgh > -78)) | |
{ | |
bars = 2; | |
} | |
else if ((RSSI_strgh < -78) & (RSSI_strgh > -82)) | |
{ | |
bars = 1; | |
} | |
else | |
{ | |
bars = 0; | |
} | |
return bars; | |
} | |
void callback(char *topic, byte *payload, unsigned int length) | |
{ | |
Serial.print("Message arrived in topic: "); | |
Serial.println(topic); | |
Serial.print("Message:"); | |
snprintf(mesage_mqtt, length+1, "%s", payload); | |
String msg(mesage_mqtt); | |
int dpct = msg.indexOf(':'); | |
int br = msg.indexOf('}'); | |
temp_int = msg.substring(dpct, br); | |
Serial.printf("%s", mesage_mqtt); | |
Serial.println(); | |
Serial.println("-----------------------"); | |
} | |
#ifdef INA219_CHECK | |
void batteryRead(void) | |
{ | |
float shuntvoltage = 0; | |
float busvoltage = 0; | |
float current_mA = 0; | |
float loadvoltage = 0; | |
float power_mW = 0; | |
shuntvoltage = ina219.getShuntVoltage_mV(); | |
busvoltage = ina219.getBusVoltage_V(); | |
current_mA = ina219.getCurrent_mA(); | |
power_mW = ina219.getPower_mW(); | |
loadvoltage = busvoltage + (shuntvoltage / 1000); | |
Serial.print("Bus Voltage: "); | |
Serial.print(busvoltage); | |
busvoltage_s = String(loadvoltage); | |
busvoltage_f = loadvoltage; | |
Serial.println(" V"); | |
Serial.print("Shunt Voltage: "); | |
Serial.print(shuntvoltage); | |
Serial.println(" mV"); | |
Serial.print("Load Voltage: "); | |
Serial.print(loadvoltage); | |
Serial.println(" V"); | |
Serial.print("Current: "); | |
Serial.print(current_mA); | |
Serial.println(" mA"); | |
Serial.print("Power: "); | |
Serial.print(power_mW); | |
Serial.println(" mW"); | |
Serial.println(""); | |
delay(2000); | |
} | |
#endif | |
void setup_clock() | |
{ | |
rtc.setTime(00, 29, 19, 10, 3, 2024); // 3th March 2024 20:18:30 | |
if (WiFi.status() == WL_CONNECTED) | |
{ | |
/*---------set with NTP---------------*/ | |
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); | |
struct tm timeinfo; | |
if (getLocalTime(&timeinfo)) | |
{ | |
rtc.setTimeStruct(timeinfo); | |
} | |
} | |
else | |
{ | |
wifi_connection = wifi_connect(); | |
} | |
} |
Todo
- Să-i adaug funcționalitatea pentru configurarea rețelei Wifi dorite și eventual configurarea certificatului
- Să alimentez placa la un INA219 și o baterie
Documentație proiect
- https://github.com/SimedruF/ESP32_LILYGOT5_WeatherStation
- https://github.com/Xinyuan-LilyGO/LilyGo-T5-Epaper-Series
- https://en.wikipedia.org/wiki/Public_key_certificate
- https://www.techtarget.com/searchsecurity/definition/public-key-certificate
Mulțumesc pentru atenție!
Pentru întrebări și/sau consultanță tehnică vă stau la dispoziție pe blog mai jos în secțiunea de comentarii sau pe email simedruflorin@automatic-house.ro.
O zi plăcută tuturor !