Remote control HA

Publicat de Florin pe

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"); }
}
Categorii: how to

0 comentarii

Lasă un răspuns

Substituent avatar

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *