Remote control HA

Am folosit un esp32 LVGL cu touch de 2.2

si am incepu sa scriu un cod :
in care avem conectare wifi , conectare mqtt . avem librarille lovyanLVGX , si cele pentru touch ,am studiat disply ul este un ST conectat paralel , si am identificat pinii . mai jos aveti codul unde puteti schimba , credentiale wifi si mqtt dar comenzile mqtt trebuie sa le gasiti nu se vor poreivi cu ce am eu ,
#include <Arduino.h> #include <LovyanGFX.hpp> #include <WiFi.h> #include <WiFiMulti.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include "CST820.h" // --- CONFIGURARE CULORI (Verde Inchis pentru vizibilitate) --- #define COL_NEON 0x03E0 // Schimbat din 0x07E0 in 0x03E0 (Verde Inchis) #define COL_OFF 0x2104 #define COL_BACK 0xA000 #define COL_PV 0xFDA0 #define COL_BMS 0x07FF #define COL_BAR 0x18C3 #define COL_BED 0x632C #define COL_TEH 0x7BCF enum Page { PAGE_HOME, PAGE_PV, PAGE_BMS, PAGE_LIVING, PAGE_BUCATARIE, PAGE_BEDROOM, PAGE_TEHNIC }; Page currentPage = PAGE_HOME; WiFiMulti wifiMulti; const char* mqtt_server = "10.11.12.100"; const char* mqtt_user = "hamqtt"; const char* mqtt_pass = "np32442p"; float solarW = 0, houseW = 0, batteryP = 0; float bmsV = 0, bmsA = 0, bmsAvg = 0, bmsT1 = 0; struct MQTTButton { const char* label; const char* cmdTopic; const char* statTopic; bool state; }; // --- BUTOANE BUCATARIE --- MQTTButton btnB[2] = { {"COFEE", "cmnd/tasmota_30A365/POWER1", "stat/tasmota_30A365/POWER1", false}, {"FILTRU", "cmnd/tasmota_30A365/POWER2", "stat/tasmota_30A365/POWER2", false} }; MQTTButton btnL[8] = { {"Tavan 1", "cmnd/Living_C8A8DF/POWER1", "stat/Living_C8A8DF/POWER1", false}, {"Tavan 2", "cmnd/Living_C8A8DF/POWER2", "stat/Living_C8A8DF/POWER2", false}, {"Socket 1", "cmnd/tasmota_1903FA/POWER1", "stat/tasmota_1903FA/POWER1", false}, {"Socket 2", "cmnd/tasmota_1903FA/POWER2", "stat/tasmota_1903FA/POWER2", false}, {"Socket 3", "cmnd/tasmota_1903FA/POWER3", "stat/tasmota_1903FA/POWER3", false}, {"IPTV", "cmnd/StripLiv2/POWER2", "stat/StripLiv2/POWER2", false}, {"Acvariu", "cmnd/StripLiv2/POWER3", "stat/StripLiv2/POWER3", false}, {"USB", "cmnd/tasmota_1903FA/POWER4", "stat/tasmota_1903FA/POWER4", false} }; MQTTButton btnBed[2] = { {"LUMINA PAT", "cmnd/bedroom/POWER1", "stat/bedroom/POWER1", false}, {"TV BED", "cmnd/bedroom/POWER2", "stat/bedroom/POWER2", false} }; MQTTButton btnTeh[2] = { {"POMPA", "cmnd/tehnic/POWER1", "stat/tehnic/POWER1", false}, {"SERVER", "cmnd/tehnic/POWER2", "stat/tehnic/POWER2", false} }; lgfx::LGFX_Device lcd; lgfx::Bus_Parallel8 bus; lgfx::Panel_ST7789 panel; CST820 touch(21, 22, -1, -1); WiFiClient espClient; PubSubClient client(espClient); uint16_t touchX, touchY; uint8_t touchGesture; // --- BARA DE STATUS --- void drawStatusBar(String title) { lcd.fillRect(0, 0, 240, 32, COL_BAR); uint16_t mqttCol = client.connected() ? COL_NEON : 0xF800; lcd.fillCircle(15, 16, 5, mqttCol); lcd.drawCircle(15, 16, 6, TFT_WHITE); lcd.setTextColor(TFT_WHITE); lcd.setFont(&fonts::Font2); lcd.drawCenterString(title, 120, 7); int rssi = WiFi.RSSI(); int bars = (rssi > -55) ? 4 : (rssi > -70) ? 3 : (rssi > -85) ? 2 : (rssi > -100) ? 1 : 0; for (int i = 0; i < 4; i++) { uint16_t barCol = (i < bars) ? COL_NEON : 0x4208; lcd.fillRect(205 + (i * 6), 22 - (i * 4), 4, 4 + (i * 4), barCol); } } void drawThickBox(int x, int y, int w, int h, uint16_t color, String label, String value) { lcd.drawRoundRect(x, y, w, h, 8, color); lcd.setTextColor(color); lcd.setFont(&fonts::Font2); lcd.drawCenterString(label, x + (w/2), y + 5); lcd.setTextColor(TFT_WHITE); lcd.setFont(&fonts::Font4); lcd.drawCenterString(value, x + (w/2), y + 25); } void renderHomePage() { lcd.fillScreen(TFT_BLACK); drawStatusBar("MENU ACASA"); lcd.drawRoundRect(10, 40, 105, 75, 10, COL_PV); lcd.setTextColor(COL_PV); lcd.drawCenterString("SOLAR PV", 62, 70); lcd.drawRoundRect(125, 40, 105, 75, 10, COL_BMS); lcd.setTextColor(COL_BMS); lcd.drawCenterString("BMS BATT", 177, 70); lcd.drawRoundRect(10, 125, 105, 75, 10, COL_NEON); lcd.setTextColor(COL_NEON); lcd.drawCenterString("LIVING", 62, 155); lcd.drawRoundRect(125, 125, 105, 75, 10, COL_NEON); lcd.setTextColor(COL_NEON); lcd.drawCenterString("BUCAT.", 177, 155); lcd.drawRoundRect(10, 210, 105, 75, 10, COL_BED); lcd.setTextColor(COL_BED); lcd.drawCenterString("BEDROOM", 62, 240); lcd.drawRoundRect(125, 210, 105, 75, 10, COL_TEH); lcd.setTextColor(COL_TEH); lcd.drawCenterString("TEHNIC", 177, 240); } void renderPVPage() { lcd.fillScreen(TFT_BLACK); drawStatusBar("MONITOR PV"); drawThickBox(45, 35, 150, 65, COL_PV, "SOLAR", String((int)solarW) + "W"); drawThickBox(10, 115, 105, 65, COL_NEON, "BATERIE", String((int)batteryP) + "%"); drawThickBox(125, 115, 105, 65, 0xF800, "RETEA", String((int)abs(houseW - solarW)) + "W"); drawThickBox(45, 205, 150, 70, COL_BMS, "CASA", String((int)houseW) + "W"); lcd.drawRoundRect(60, 285, 120, 30, 8, COL_BACK); lcd.setTextColor(COL_BACK); lcd.drawCenterString("INAPOI", 120, 292); } void renderBMSPage() { lcd.fillScreen(TFT_BLACK); drawStatusBar("BMS BATERIE"); drawThickBox(10, 40, 220, 80, COL_BMS, "TENSIUNE", String(bmsV, 2) + "V"); drawThickBox(10, 130, 220, 70, COL_NEON, "CURENT", String(bmsA, 1) + "A"); drawThickBox(10, 215, 105, 70, COL_PV, "CELL AVG", String(bmsAvg, 3) + "V"); drawThickBox(125, 215, 105, 70, COL_PV, "TEMP", String(bmsT1, 1) + "C"); lcd.drawRoundRect(60, 285, 120, 30, 8, COL_BACK); lcd.setTextColor(COL_BACK); lcd.drawCenterString("INAPOI", 120, 292); } void renderGenericPage(String title, MQTTButton* buttons, int count) { lcd.fillScreen(TFT_BLACK); drawStatusBar(title); for (int i = 0; i < count; i++) { int y = 50 + (i * 110); uint16_t color = buttons[i].state ? COL_NEON : COL_OFF; if(buttons[i].state) lcd.fillRoundRect(10, y, 220, 95, 15, color); else lcd.drawRoundRect(10, y, 220, 95, 15, color); lcd.setTextColor(TFT_WHITE); lcd.setFont(&fonts::Font4); lcd.drawCenterString(buttons[i].label, 120, y + 20); lcd.setFont(&fonts::Font2); lcd.drawCenterString(buttons[i].state ? "PORNIT" : "OPRIT", 120, y + 60); } lcd.drawRoundRect(60, 280, 120, 30, 8, COL_BACK); lcd.setTextColor(COL_BACK); lcd.drawCenterString("INAPOI", 120, 287); } void renderLivingPage() { lcd.fillScreen(TFT_BLACK); drawStatusBar("LIVING"); for (int i = 0; i < 8; i++) { int x = 10 + (i % 2) * 115; int y = 35 + (i / 2) * 62; uint16_t col = btnL[i].state ? COL_NEON : COL_OFF; if(btnL[i].state) { lcd.fillRoundRect(x, y, 105, 55, 8, col); lcd.setTextColor(TFT_WHITE); } // Text alb pe verde inchis else { lcd.drawRoundRect(x, y, 105, 55, 8, col); lcd.setTextColor(TFT_WHITE); } lcd.setFont(&fonts::Font2); lcd.drawCenterString(btnL[i].label, x + 52, y + 18); } lcd.drawRoundRect(60, 290, 120, 25, 5, COL_BACK); lcd.setTextColor(COL_BACK); lcd.drawCenterString("INAPOI", 120, 295); } void callback(char* topic, byte* payload, unsigned int length) { String t = String(topic); String m = ""; for (int i = 0; i < length; i++) m += (char)payload[i]; for (int i = 0; i < 2; i++) if (t == btnB[i].statTopic) btnB[i].state = (m == "ON"); for (int i = 0; i < 8; i++) if (t == btnL[i].statTopic) btnL[i].state = (m == "ON"); for (int i = 0; i < 2; i++) if (t == btnBed[i].statTopic) btnBed[i].state = (m == "ON"); for (int i = 0; i < 2; i++) if (t == btnTeh[i].statTopic) btnTeh[i].state = (m == "ON"); if (t == "tele/Rail_Tehnic/SENSOR") { JsonDocument doc; if (!deserializeJson(doc, payload, length)) houseW = doc["ENERGY"]["Power"]; } else if (t.startsWith("sensor/") || t.startsWith("dalybms/")) { float val = m.toFloat(); if (t == "sensor/solar_production") solarW = val; if (t == "sensor/battery_level") batteryP = val; if (t == "dalybms/sensor/dalybms_total_voltage/state") bmsV = val; if (t == "dalybms/sensor/dalybms_current/state") bmsA = val; if (t == "dalybms/sensor/dalybms_average_cell_voltage/state") bmsAvg = val; if (t == "dalybms/sensor/dalybms_temperature_1/state") bmsT1 = val; } if (currentPage == PAGE_PV) renderPVPage(); else if (currentPage == PAGE_BMS) renderBMSPage(); else if (currentPage == PAGE_LIVING) renderLivingPage(); else if (currentPage == PAGE_BUCATARIE) renderGenericPage("BUCATARIE", btnB, 2); else if (currentPage == PAGE_BEDROOM) renderGenericPage("BEDROOM", btnBed, 2); else if (currentPage == PAGE_TEHNIC) renderGenericPage("TEHNIC", btnTeh, 2); } void reconnect() { if (!client.connected()) { if (client.connect("ESP32_Master_Final", mqtt_user, mqtt_pass)) { client.subscribe("stat/+/+"); client.subscribe("tele/Rail_Tehnic/SENSOR"); client.subscribe("sensor/#"); client.subscribe("dalybms/sensor/+/state"); } } } void handleTouch(int x, int y) { if (currentPage == PAGE_HOME) { if (y > 40 && y < 115) { if (x < 120) { currentPage = PAGE_PV; renderPVPage(); } else { currentPage = PAGE_BMS; renderBMSPage(); } } else if (y > 125 && y < 200) { if (x < 120) { currentPage = PAGE_LIVING; for(int i=0; i<8; i++) client.publish(btnL[i].cmdTopic, ""); renderLivingPage(); } else { currentPage = PAGE_BUCATARIE; for(int i=0; i<2; i++) client.publish(btnB[i].cmdTopic, ""); renderGenericPage("BUCATARIE", btnB, 2); } } else if (y > 210 && y < 285) { if (x < 120) { currentPage = PAGE_BEDROOM; for(int i=0; i<2; i++) client.publish(btnBed[i].cmdTopic, ""); renderGenericPage("BEDROOM", btnBed, 2); } else { currentPage = PAGE_TEHNIC; for(int i=0; i<2; i++) client.publish(btnTeh[i].cmdTopic, ""); renderGenericPage("TEHNIC", btnTeh, 2); } } } else { if (y > 270) { currentPage = PAGE_HOME; renderHomePage(); return; } if (currentPage == PAGE_BUCATARIE) { if (y > 50 && y < 145) client.publish(btnB[0].cmdTopic, btnB[0].state ? "OFF" : "ON"); else if (y > 160 && y < 255) client.publish(btnB[1].cmdTopic, btnB[1].state ? "OFF" : "ON"); } else if (currentPage == PAGE_BEDROOM) { if (y > 50 && y < 145) client.publish(btnBed[0].cmdTopic, btnBed[0].state ? "OFF" : "ON"); else if (y > 160 && y < 255) client.publish(btnBed[1].cmdTopic, btnBed[1].state ? "OFF" : "ON"); } else if (currentPage == PAGE_TEHNIC) { if (y > 50 && y < 145) client.publish(btnTeh[0].cmdTopic, btnTeh[0].state ? "OFF" : "ON"); else if (y > 160 && y < 255) client.publish(btnTeh[1].cmdTopic, btnTeh[1].state ? "OFF" : "ON"); } else if (currentPage == PAGE_LIVING) { if (y > 35 && y < 285) { int id = ((y - 35) / 62) * 2 + (x / 120); if (id >= 0 && id < 8) client.publish(btnL[id].cmdTopic, btnL[id].state ? "OFF" : "ON"); } } } } void setup() { Serial.begin(115200); auto bus_cfg = bus.config(); bus_cfg.pin_wr = 4; bus_cfg.pin_rd = 2; bus_cfg.pin_rs = 16; bus_cfg.pin_d0 = 15; bus_cfg.pin_d1 = 13; bus_cfg.pin_d2 = 12; bus_cfg.pin_d3 = 14; bus_cfg.pin_d4 = 27; bus_cfg.pin_d5 = 25; bus_cfg.pin_d6 = 33; bus_cfg.pin_d7 = 32; bus.config(bus_cfg); auto panel_cfg = panel.config(); panel_cfg.pin_cs = 17; panel_cfg.pin_rst = -1; panel.config(panel_cfg); panel.setBus(&bus); lcd.setPanel(&panel); lcd.init(); lcd.setRotation(0); renderHomePage(); wifiMulti.addAP("ReteauaMea", "internaut123"); wifiMulti.addAP("Nume_Backup", "parola_backup"); while (wifiMulti.run() != WL_CONNECTED) { delay(100); } client.setServer(mqtt_server, 1883); client.setCallback(callback); touch.begin(); } void loop() { wifiMulti.run(); if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) reconnect(); client.loop(); } if (touch.getTouch(&touchX, &touchY, &touchGesture)) { handleTouch(touchX, touchY); delay(350); } static unsigned long lu = 0; if (millis() - lu > 5000) { lu = millis(); drawStatusBar(currentPage == PAGE_HOME ? "MENU ACASA" : "CONTROL"); } }
0 comentarii