duminică, 22 februarie 2026

Ceas cu termometru, display LCD, emitator WiFi

 Va salut !

Tot cu ajutorul AI am realizat un ceas, cu Wemos D1 mini, care afiseaza pe un dispay LCD si temperatura citita cu SHT40, transmisa din exteriorul locuintei, tot de un Wemos D1 mini . Dupa multe teste si multe buguri rezolvate, pot spune ca acum functioneaza foarte bine, nu am mai gasit nicio problema.Trecerea la ora de vara/iarna se face automat.

Ceasul propriu-zis il alimentez dintr-un alimentator de telefon mobil, de 5 volti. Emitatorul este alimentat dintr-un acumulator Li-Ion, a carui tensiune este citita periodic ; daca scade sub pragul critic, apare mesajul "ACCU" pe displayul ceasului. Consumul emitatorului este foarte mic pentru ca transmisia temperaturii se face o data la 5 minute, dupa care montajul intra in deep sleep. Alimentarea se face cu un IC specializat, HT7333. 


 

 


 

// RECEIVER CU - HTTP STABIL CU NON-BLOCKING LOOP

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <TFT_eSPI.h>
#include <TimeLib.h>
#include <Timezone.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

TFT_eSPI display = TFT_eSPI();
ESP8266WebServer server(80);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000);

const char* ssid = "Andy_2.4G";
const char* password = "andy1603";

TimeChangeRule EEST = {"EEST", Last, Sun, Mar, 3, 180};
TimeChangeRule EET = {"EET", Last, Sun, Oct, 3, 120};
Timezone Bucharest(EEST, EET);

const char* zileAbrev[] = {"DU", "LU", "MA", "MI", "JO", "VI", "SA"};
const char* luni[] = {"IAN", "FEB", "MAR", "APR", "MAI", "IUN", "IUL", "AUG", "SEP", "OCT", "NOV", "DEC"};

float receivedTemp = 0.0;
bool lowBattery = false;

void handleUpdate() {
if (server.hasArg("temp")) {
float v = server.arg("temp").toFloat();
if (v >= -50 && v <= 100) receivedTemp = v;
}
lowBattery = (server.hasArg("bat") && server.arg("bat") == "LOW");
server.send(200, "text/plain", "OK");
}

unsigned long prevDisplay = 0;
unsigned long prevNTP = 0;

void displayInfo() {
time_t utc = timeClient.getEpochTime();
time_t local = (utc > 100000000) ? Bucharest.toLocal(utc) : 0;

int dd=1, mm=0, wd=1, h=0, m=0, s=0;
if (utc > 100000000) {
tmElements_t tm; breakTime(local, tm);
dd=tm.Day; mm=tm.Month-1; wd=tm.Wday-1; h=tm.Hour; m=tm.Minute; s=tm.Second;
}

// ORĂ
static int lh=-1, lm=-1;
if (h!=lh || m!=lm || utc<=100000000) {
display.fillRect(20,80,220,80,TFT_BLACK);
display.setTextFont(7); display.setTextColor(TFT_CYAN,TFT_BLACK); display.setTextDatum(TR_DATUM);
display.drawString((utc>100000000)?(String(h)+":"+(m<10?"0":"")+String(m)):"--:--", 175, 95);
lh=h; lm=m;
}

// SECUNDE
static String ls="";
String sec=(utc>100000000)?(s<10?"0":"")+String(s):"--";
if (sec!=ls) {
display.setFreeFont(&FreeSansBold12pt7b); display.setTextDatum(MC_DATUM);
display.setTextColor(TFT_CYAN,TFT_BLACK); display.fillRect(173,100,60,30,TFT_BLACK);
display.drawString(sec,190,105); ls=sec;
}

// DATĂ
static String ld="";
String dat=(utc>100000000)?String(dd)+"-"+String(luni[mm]):"-- ---";
if (dat!=ld) {
display.setFreeFont(&FreeSansBold12pt7b); display.setTextDatum(TL_DATUM);
display.setTextColor(TFT_GREEN,TFT_BLACK); display.fillRect(10,25,100,25,TFT_BLACK);
display.drawString(dat,0,25); ld=dat;
}

// TEMPERATURĂ - FOARTE IMPORTANT: afișează mereu, chiar dacă este 0.0
static String lt="";
String tmp=String(receivedTemp,1)+"'C";
if (tmp!=lt || receivedTemp==0.0) { // 🔑 FORȚEAZĂ afișarea inițială!
display.fillRect(233-90,25-2,90,25,TFT_BLACK);
display.setFreeFont(&FreeSansBold12pt7b); display.setTextDatum(TR_DATUM);
display.setTextColor(TFT_PURPLE,TFT_BLACK); display.drawString("'C",233,25);
display.setTextColor(TFT_YELLOW,TFT_BLACK); display.drawString(String(receivedTemp,1),233-display.textWidth("'C"),25);
lt=tmp;
}

// BATERIE
static bool lb=false;
if (lowBattery!=lb) {
display.fillRect(95,17,50,20,TFT_BLACK);
if (lowBattery) {
display.setTextFont(2); display.setTextDatum(MC_DATUM);
display.setTextColor(TFT_RED,TFT_BLACK); display.drawString("ACCU",120,25);
}
lb=lowBattery;
}

// ZILE
static int lw=-1;
int cw=(wd==0)?6:wd-1;
if (cw!=lw || utc<=100000000) {
display.fillRect(0,185,240,30,TFT_BLACK);
display.setFreeFont(&FreeSansBold9pt7b); display.setTextDatum(MC_DATUM);
int pz[7]={10,50,90,125,155,185,220};
for (int i=0;i<7;i++) {
int zi=(i+1)%7;
uint16_t c=(utc<=100000000)?TFT_DARKGREY:(i==cw)?(zi==0||zi==6?TFT_RED:TFT_GREEN):TFT_DARKGREY;
display.setTextColor(c,TFT_BLACK); display.drawString(zileAbrev[zi],pz[i],200);
}
lw=cw;
}
}

void setup() {
Serial.begin(115200);
display.init();
display.setRotation(3);
display.fillScreen(TFT_BLACK);

display.setTextColor(TFT_WHITE, TFT_BLACK);
display.setFreeFont(&FreeSansBold12pt7b);
display.setTextDatum(MC_DATUM);

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);

int attempts = 0;
const int maxAttempts = 15;

// Bucla de conectare cu actualizare pe ecran
while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
attempts++;

display.fillScreen(TFT_BLACK);
display.drawString("Conectare WiFi...", 120, 100);
// Afișează încercarea curentă (ex: 1/15, 2/15...)
display.drawString(String(attempts) + "/" + String(maxAttempts), 120, 140);

//Serial.print("Incercarea: "); Serial.println(attempts);
delay(1000); // Așteaptă 1 secundă între încercări pentru a da timp routerului
}

// Verificăm dacă am reușit sau am epuizat tentativele
if (WiFi.status() == WL_CONNECTED) {
display.fillScreen(TFT_BLACK);
display.drawString("Conectat !", 120, 100);
display.drawString(WiFi.localIP().toString(), 120, 140);

timeClient.begin();
timeClient.update();
server.on("/update", handleUpdate);
server.begin();

delay(2000);
} else {
display.fillScreen(TFT_BLACK);
display.setTextColor(TFT_RED, TFT_BLACK); // Opțional: roșu pentru eroare
display.drawString("Eroare WiFi !", 120, 100);
display.drawString("Reboot...", 120, 140);
delay(3000);
ESP.restart();
}
}


void loop() {
// 🔑 CRITIC: server.handleClient() la FIECARE ITERAȚIE (fără excepții!)
server.handleClient(); // NICIODATĂ nu blochează mai mult de 1ms

// NTP non-blocking (doar la intervale)
if (millis() - prevNTP > 900000 && timeClient.update()) prevNTP = millis();

// Afișaj la 1s (fără blocări)
if (millis() - prevDisplay >= 1000) {
prevDisplay = millis();
displayInfo();
}
}
<10 175="" 95="" lh="h;" lm="m;" ls="" m="" sec="(utc" secunde="" static="" string="" tring=""><10 dat="(utc" display.drawstring="" display.fillrect="" display.setfreefont="" display.settextcolor="" display.settextdatum="" if="" ld="" ls="sec;" reesansbold12pt7b="" s="" sec="" static="" string="" tring=""><7 -="" 100="" 120="" 140="" 1="" 1ms="" 2="" a="" actualizare="" afi="" am="" attempts="" blocheaz="" bucla="" c="" conectare="" const="" critic:="" cu="" curent="" da="" dac="" de="" delay="" display.drawstring="" display.fillscreen="" display.init="" display.setfreefont="" display.setrotation="" display.settextcolor="" display.settextdatum="" doar="" eaz="" eboot...="" ecran="" else="" epuizat="" erial.print="" eroare="" esp.restart="" ex:="" excep="" f="" fiecare="" handleupdate="" i="" if="" ifi.localip="" ifi.status="" ii="" int="" intervale="" ional:="" it="" itera="" la="" loop="" lw="cw;" m="" mai="" maxattempts="" millis="" mult="" ncerc="" ncercarea:="" ncercarea="" niciodat="" non-blocking="" ntp="" ntre="" nu="" onectare="" onectat="" op="" password="" pe="" pentru="" prevntp="" pz="" r="" reesansbold12pt7b="" reu="" ri="" ro="" roare="" routerului="" sau="" secund="" serial.begin="" serial.println="" server.begin="" server.handleclient="" server.on="" setup="" ssid="" string="" teapt="" tentativele="" tft_black="" timeclient.begin="" timeclient.update="" timp="" tostring="" tring="" u="" uint16_t="" update="" verific="" void="" while="" wifi...="" wifi.begin="" wifi.mode="" wifi="" wl_connected="" zi="" zileabrev="">

Niciun comentariu:

Trimiteți un comentariu