From 2aa5e59feab2793261a17410724b5f7ea245af41 Mon Sep 17 00:00:00 2001 From: fvanroie Date: Sat, 1 Feb 2020 19:01:16 +0100 Subject: [PATCH] Add dispatch and calibrate --- src/hasp.cpp | 152 ++++++++++++++++-------------------------- src/hasp.h | 5 +- src/hasp_dispatch.cpp | 103 ++++++++++++++++++++++++++++ src/hasp_dispatch.h | 15 +++++ src/hasp_gui.cpp | 42 ++++++++++-- src/hasp_gui.h | 3 + src/hasp_http.cpp | 6 +- src/hasp_http.h | 1 + src/hasp_mqtt.cpp | 128 +++++++++++++---------------------- src/hasp_mqtt.h | 1 + src/hasp_tft.cpp | 22 ------ src/hasp_tft.h | 1 + src/hasp_wifi.cpp | 9 +-- 13 files changed, 269 insertions(+), 219 deletions(-) create mode 100644 src/hasp_dispatch.cpp create mode 100644 src/hasp_dispatch.h diff --git a/src/hasp.cpp b/src/hasp.cpp index 5cb8e973..ff633571 100644 --- a/src/hasp.cpp +++ b/src/hasp.cpp @@ -36,11 +36,11 @@ * DEFINES *********************/ -uint8_t haspStartPage = 0; -uint8_t haspThemeId = 0; -uint16_t haspThemeHue = 200; -String haspPagesPath; -String haspZiFontPath; +uint8_t haspStartPage = 0; +uint8_t haspThemeId = 0; +uint16_t haspThemeHue = 200; +char haspPagesPath[32] = "/pages.jsonl\0"; +char haspZiFontPath[32]; /********************** * TYPEDEFS @@ -256,6 +256,11 @@ void haspSendNewValue(lv_obj_t * obj, const char * txt) } } +void haspSendNewValue(lv_obj_t * obj, int16_t val) +{ + haspSendNewValue(obj, (int32_t)val); +} + int32_t get_cpicker_value(lv_obj_t * obj) { lv_color16_t c16; @@ -263,11 +268,6 @@ int32_t get_cpicker_value(lv_obj_t * obj) return (int32_t)c16.full; } -void haspSendNewValue(lv_obj_t * obj, int16_t val) -{ - haspSendNewValue(obj, (int32_t)val); -} - void haspSendNewValue(lv_obj_t * obj, lv_color_t color) { haspSendNewValue(obj, get_cpicker_value(obj)); @@ -457,9 +457,6 @@ bool haspGetObjAttribute(lv_obj_t * obj, String strAttr, std::string & strPayloa return false; } -void haspSetAttr(String strTopic, String strPayload) -{} - void haspSetObjAttribute(lv_obj_t * obj, String strAttr, String strPayload) { if(!obj) return; @@ -551,37 +548,22 @@ void haspSetObjAttribute(lv_obj_t * obj, String strAttr, String strPayload) } } -void haspProcessAttribute(String strTopic, String strPayload) +void haspProcessAttribute(uint8_t pageid, uint8_t objid, String strAttr, String strPayload) { - if(strTopic.startsWith("p[")) { - String strPageId = strTopic.substring(2, strTopic.indexOf("]")); - String strTemp = strTopic.substring(strTopic.indexOf("]") + 1, strTopic.length()); - if(strTemp.startsWith(".b[")) { - String strObjId = strTemp.substring(3, strTemp.indexOf("]")); - String strAttr = strTemp.substring(strTemp.indexOf("]") + 1, strTemp.length()); - debugPrintln(strPageId + " && " + strObjId + " && " + strAttr); - - int pageid = strPageId.toInt(); - int objid = strObjId.toInt(); - - if(pageid >= 0 && pageid <= 255 && objid > 0 && objid <= 255) { - lv_obj_t * obj = FindObjFromId((uint8_t)pageid, (uint8_t)objid); - if(obj) { - if(strPayload != "") - haspSetObjAttribute(obj, strAttr, strPayload); - else { - /* publish the change */ - std::string strValue = ""; - if(haspGetObjAttribute(obj, strAttr, strValue)) { - mqttSendNewValue(pageid, objid, String(strValue.c_str())); - } else { - warningPrintln(String(F("HASP: %sUnknown property: ")) + strAttr); - } - } // payload - } // obj - } // valid page - } - } + lv_obj_t * obj = FindObjFromId((uint8_t)pageid, (uint8_t)objid); + if(obj) { + if(strPayload != "") + haspSetObjAttribute(obj, strAttr, strPayload); + else { + /* publish the change */ + std::string strValue = ""; + if(haspGetObjAttribute(obj, strAttr, strValue)) { + mqttSendNewValue(pageid, objid, String(strValue.c_str())); + } else { + warningPrintln(String(F("HASP: %sUnknown property: ")) + strAttr); + } + } // payload + } // obj } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -687,7 +669,6 @@ void haspDisplayAP(const char * ssid, const char * pass) void haspSetup(JsonObject settings) { char buffer[64]; - haspPagesPath = F("/pages.jsonl"); haspSetConfig(settings); @@ -706,66 +687,66 @@ void haspSetup(JsonObject settings) // static lv_font_t * // my_font = (lv_font_t *)lv_mem_alloc(sizeof(lv_font_t)); - my_font = (lv_font_t *)lv_mem_alloc(sizeof(lv_font_t)); + my_font[0] = (lv_font_t *)lv_mem_alloc(sizeof(lv_font_t)); lv_zifont_init(); - if(lv_zifont_font_init(my_font, haspZiFontPath.c_str(), 24) != 0) { - errorPrintln(String(F("HASP: %sFailed to set the custom font to ")) + haspZiFontPath); - my_font = NULL; // Use default font + if(lv_zifont_font_init(my_font[0], haspZiFontPath, 24) != 0) { + errorPrintln(String(F("HASP: %sFailed to set the custom font to ")) + String(haspZiFontPath)); + my_font[0] = NULL; // Use default font } lv_theme_t * th; switch(haspThemeId) { #if LV_USE_THEME_ALIEN == 1 case 1: - th = lv_theme_alien_init(haspThemeHue, my_font); + th = lv_theme_alien_init(haspThemeHue, my_font[0]); break; #endif #if LV_USE_THEME_NIGHT == 1 case 2: - th = lv_theme_night_init(haspThemeHue, my_font); // heavy + th = lv_theme_night_init(haspThemeHue, my_font[0]); // heavy break; #endif #if LV_USE_THEME_MONO == 1 case 3: - th = lv_theme_mono_init(haspThemeHue, my_font); // lightweight + th = lv_theme_mono_init(haspThemeHue, my_font[0]); // lightweight break; #endif #if LV_USE_THEME_MATERIAL == 1 case 4: - th = lv_theme_material_init(haspThemeHue, my_font); + th = lv_theme_material_init(haspThemeHue, my_font[0]); break; #endif #if LV_USE_THEME_ZEN == 1 case 5: - th = lv_theme_zen_init(haspThemeHue, my_font); // lightweight + th = lv_theme_zen_init(haspThemeHue, my_font[0]); // lightweight break; #endif #if LV_USE_THEME_NEMO == 1 case 6: - th = lv_theme_nemo_init(haspThemeHue, my_font); // heavy + th = lv_theme_nemo_init(haspThemeHue, my_font[0]); // heavy break; #endif #if LV_USE_THEME_TEMPL == 1 case 7: - th = lv_theme_templ_init(haspThemeHue, my_font); // lightweight, not for production... + th = lv_theme_templ_init(haspThemeHue, my_font[0]); // lightweight, not for production... break; #endif #if LV_USE_THEME_HASP == 1 case 8: - th = lv_theme_hasp_init(haspThemeHue, my_font); + th = lv_theme_hasp_init(haspThemeHue, my_font[0]); break; #endif case 0: #if LV_USE_THEME_DEFAULT == 1 - th = lv_theme_default_init(haspThemeHue, my_font); + th = lv_theme_default_init(haspThemeHue, my_font[0]); #else - th = lv_theme_hasp_init(512, my_font); + th = lv_theme_hasp_init(512, my_font[0]); #endif break; default: - th = lv_theme_hasp_init(512, my_font); + th = lv_theme_hasp_init(512, my_font[0]); debugPrintln(F("HASP: Unknown theme selected")); } @@ -799,6 +780,10 @@ void haspSetup(JsonObject settings) haspLoadPage(haspPagesPath); haspSetPage(haspStartPage); + // lv_obj_t * img_bin_t = lv_img_create(pages[current_page], NULL); /*Crate an image object*/ + // lv_img_set_src(img_bin_t, "F:/dogsmall(1).bin"); /*Set the created file as image (a red rose)*/ + // lv_obj_set_pos(img_bin_t, 64, 64); /*Set the positions*/ + // // lv_page_set_style(page, LV_PAGE_STYLE_SB, &style_sb); /*Set the scrollbar style*/ // // lv_obj_t *img1 = lv_img_create(pages[2], NULL); @@ -1027,6 +1012,11 @@ static void switch_event_handler(lv_obj_t * obj, lv_event_t event) if(event == LV_EVENT_VALUE_CHANGED) haspSendNewValue(obj, lv_sw_get_state(obj)); } +static void checkbox_event_handler(lv_obj_t * obj, lv_event_t event) +{ + if(event == LV_EVENT_VALUE_CHANGED) haspSendNewValue(obj, lv_cb_is_checked(obj)); +} + static void ddlist_event_handler(lv_obj_t * obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { @@ -1049,10 +1039,10 @@ static void roller_event_handler(lv_obj_t * obj, lv_event_t event) /////////////////////////////////////////////////////////////////////////////////////////////////////////// -void haspReset() +void haspReset(bool write_config) { mqttStop(); // Stop the MQTT Client first - configWriteConfig(); + if(write_config) configWriteConfig(); debugStop(); delay(250); wifiStop(); @@ -1159,7 +1149,7 @@ void haspNewObject(const JsonObject & config) case LV_HASP_CHECKBOX: { obj = lv_cb_create(parent_obj, NULL); if(config[F("txt")]) lv_cb_set_text(obj, config[F("txt")].as().c_str()); - lv_obj_set_event_cb(obj, switch_event_handler); + lv_obj_set_event_cb(obj, checkbox_event_handler); break; } case LV_HASP_LABEL: { @@ -1360,11 +1350,6 @@ void haspLoadPage(String pages) bool haspGetConfig(const JsonObject & settings) { - if(!settings.isNull() && settings[FPSTR(F_CONFIG_STARTPAGE)] == haspStartPage && - settings[FPSTR(F_CONFIG_THEME)] == haspThemeId && settings[FPSTR(F_CONFIG_HUE)] == haspThemeHue && - settings[FPSTR(F_CONFIG_ZIFONT)] == haspZiFontPath && settings[FPSTR(F_CONFIG_PAGES)] == haspPagesPath) - return false; - settings[FPSTR(F_CONFIG_STARTPAGE)] = haspStartPage; settings[FPSTR(F_CONFIG_THEME)] = haspThemeId; settings[FPSTR(F_CONFIG_HUE)] = haspThemeHue; @@ -1381,55 +1366,30 @@ bool haspGetConfig(const JsonObject & settings) bool haspSetConfig(const JsonObject & settings) { - if(!settings.isNull() && settings[FPSTR(F_CONFIG_STARTPAGE)] == haspStartPage && - settings[FPSTR(F_CONFIG_THEME)] == haspThemeId && settings[FPSTR(F_CONFIG_HUE)] == haspThemeHue && - settings[FPSTR(F_CONFIG_ZIFONT)] == haspZiFontPath && settings[FPSTR(F_CONFIG_PAGES)] == haspPagesPath) - return false; - bool changed = false; if(!settings[FPSTR(F_CONFIG_PAGES)].isNull()) { - if(haspPagesPath != settings[FPSTR(F_CONFIG_PAGES)].as().c_str()) { - debugPrintln(F("haspPagesPath changed")); - } - changed |= haspPagesPath != settings[FPSTR(F_CONFIG_PAGES)].as().c_str(); - - haspPagesPath = settings[FPSTR(F_CONFIG_PAGES)].as().c_str(); + changed |= strcmp(haspPagesPath, settings[FPSTR(F_CONFIG_PAGES)]) != 0; + strncpy(haspPagesPath, settings[FPSTR(F_CONFIG_PAGES)], sizeof(haspPagesPath)); } if(!settings[FPSTR(F_CONFIG_ZIFONT)].isNull()) { - if(haspZiFontPath != settings[FPSTR(F_CONFIG_ZIFONT)].as().c_str()) { - debugPrintln(F("haspZiFontPath changed")); - } - changed |= haspZiFontPath != settings[FPSTR(F_CONFIG_ZIFONT)].as().c_str(); - - haspZiFontPath = settings[FPSTR(F_CONFIG_ZIFONT)].as().c_str(); + changed |= strcmp(haspZiFontPath, settings[FPSTR(F_CONFIG_ZIFONT)]) != 0; + strncpy(haspZiFontPath, settings[FPSTR(F_CONFIG_ZIFONT)], sizeof(haspZiFontPath)); } if(!settings[FPSTR(F_CONFIG_STARTPAGE)].isNull()) { - if(haspStartPage != settings[FPSTR(F_CONFIG_STARTPAGE)].as()) { - debugPrintln(F("haspStartPage changed")); - } changed |= haspStartPage != settings[FPSTR(F_CONFIG_STARTPAGE)].as(); - haspStartPage = settings[FPSTR(F_CONFIG_STARTPAGE)].as(); } if(!settings[FPSTR(F_CONFIG_THEME)].isNull()) { - if(haspThemeId != settings[FPSTR(F_CONFIG_THEME)].as()) { - debugPrintln(F("haspThemeId changed")); - } changed |= haspThemeId != settings[FPSTR(F_CONFIG_THEME)].as(); - haspThemeId = settings[FPSTR(F_CONFIG_THEME)].as(); } if(!settings[FPSTR(F_CONFIG_HUE)].isNull()) { - if(haspThemeHue != settings[FPSTR(F_CONFIG_HUE)].as()) { - debugPrintln(F("haspStartPage changed")); - } changed |= haspThemeHue != settings[FPSTR(F_CONFIG_HUE)].as(); - haspThemeHue = settings[FPSTR(F_CONFIG_HUE)].as(); } diff --git a/src/hasp.h b/src/hasp.h index 99a8a3c4..7a14e94c 100644 --- a/src/hasp.h +++ b/src/hasp.h @@ -77,11 +77,10 @@ void haspSetNodename(String name); String haspGetNodename(); float haspGetVersion(); void haspBackground(uint16_t pageid, uint16_t imageid); -void haspReset(); +void haspReset(bool write_config); void haspSetLabelText(String value); -void haspProcessAttribute(String strTopic, String strPayload); -void haspSetAttr(String strTopic, String strPayload); +void haspProcessAttribute(uint8_t pageid, uint8_t objid, String strAttr, String strPayload); void haspSendCmd(String nextionCmd); void haspParseJson(String & strPayload); diff --git a/src/hasp_dispatch.cpp b/src/hasp_dispatch.cpp new file mode 100644 index 00000000..6770ab43 --- /dev/null +++ b/src/hasp_dispatch.cpp @@ -0,0 +1,103 @@ +#include "hasp_dispatch.h" +#include "hasp_mqtt.h" +#include "hasp_http.h" +#include "hasp_mdns.h" +#include "hasp_wifi.h" +#include "hasp_log.h" +#include "hasp_gui.h" +#include "hasp.h" + +void dispatchSetup() +{} + +void dispatchLoop() +{} + +// objectattribute=value +void dispatchAttribute(String & strTopic, String & strPayload) +{ + if(strTopic.startsWith("p[")) { + String strPageId = strTopic.substring(2, strTopic.indexOf("]")); + String strTemp = strTopic.substring(strTopic.indexOf("]") + 1, strTopic.length()); + if(strTemp.startsWith(".b[")) { + String strObjId = strTemp.substring(3, strTemp.indexOf("]")); + String strAttr = strTemp.substring(strTemp.indexOf("]") + 1, strTemp.length()); + // debugPrintln(strPageId + " && " + strObjId + " && " + strAttr); + + int pageid = strPageId.toInt(); + int objid = strObjId.toInt(); + + if(pageid >= 0 && pageid <= 255 && objid > 0 && objid <= 255) { + haspProcessAttribute((uint8_t)pageid, (uint8_t)objid, strAttr, strPayload); + } // valid page + } + } else if(strTopic == "page") { + } else if(strTopic == "dim") { + } +} + +void dispatchPage(String & strPageid) +{ + debugPrintln("PAGE:" + strPageid); + + if(strPageid.length() == 0) { + String strPayload = String(haspGetPage()); + mqttSendState("page", strPayload.c_str()); + } else { + if(strPageid.toInt() <= 250) haspSetPage(strPageid.toInt()); + } +} + +void dispatchCommand(String cmnd) +{ + debugPrintln("CMND: " + cmnd); + + if(cmnd == "calibrate") { + guiCalibrate(); + return; + } + + if(cmnd == "restart") { + haspReset(true); + return; + } + + if(cmnd == "" || cmnd == "statusupdate") { + haspReset(true); + return; + } + + int pos = cmnd.indexOf("="); + if(pos > 0) { + String strTopic = cmnd.substring(0, pos); + String strPayload = cmnd.substring(pos + 1, cmnd.length()); + debugPrintln("CMND: '" + strTopic + "'='" + strPayload + "'"); + dispatchAttribute(strTopic, strPayload); + } +} + +void dispatchJson(String & strPayload) +{ // Parse an incoming JSON array into individual commands + if(strPayload.endsWith(",]")) { + // Trailing null array elements are an artifact of older Home Assistant automations + // and need to be removed before parsing by ArduinoJSON 6+ + strPayload.remove(strPayload.length() - 2, 2); + strPayload.concat("]"); + } + DynamicJsonDocument haspCommands(2048 + 1024); + DeserializationError jsonError = deserializeJson(haspCommands, strPayload); + if(jsonError) { // Couldn't parse incoming JSON command + errorPrintln(String(F("JSON: %sFailed to parse incoming JSON command with error: ")) + + String(jsonError.c_str())); + return; + } + + for(uint8_t i = 0; i < haspCommands.size(); i++) { + dispatchCommand(haspCommands[i]); + } +} + +void dispatchIdle(const __FlashStringHelper * state) +{ + mqttSendState(String(F("idle")).c_str(), String(state).c_str()); +} \ No newline at end of file diff --git a/src/hasp_dispatch.h b/src/hasp_dispatch.h new file mode 100644 index 00000000..57d590e4 --- /dev/null +++ b/src/hasp_dispatch.h @@ -0,0 +1,15 @@ +#ifndef HASP_DISPATCH_H +#define HASP_DISPATCH_H + +#include + +void dispatchSetup(void); +void dispatchLoop(void); + +void dispatchAttribute(String & strTopic, String & strPayload); +void dispatchCommand(String cmnd); +void dispatchJson(String & strPayload); +void dispatchPage(String & strPageid); +void dispatchIdle(const __FlashStringHelper * state); + +#endif \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 85f64c8d..3dbf2c92 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -1,7 +1,8 @@ #include -#include "lvgl.h" #include "lv_conf.h" +#include "lvgl.h" +#include "lv_fs_if.h" #include "TFT_eSPI.h" @@ -13,6 +14,7 @@ #include "hasp_log.h" #include "hasp_debug.h" #include "hasp_config.h" +#include "hasp_dispatch.h" #include "hasp_gui.h" #define LVGL_TICK_PERIOD 30 // 30 @@ -20,14 +22,15 @@ uint16_t guiSleepTime = 150; // 0.1 second resolution bool guiSleeping = false; uint8_t guiTickPeriod = 50; -Ticker tick; /* timer for interrupt handler */ -TFT_eSPI tft = TFT_eSPI(); /* TFT instance */ +Ticker tick; /* timer for interrupt handler */ +TFT_eSPI tft = TFT_eSPI(); /* TFT instance */ +uint16_t calData[5] = {0, 0, 0, 0, 0}; bool IRAM_ATTR guiCheckSleep() { bool shouldSleep = lv_disp_get_inactive_time(NULL) > guiSleepTime * 100; if(shouldSleep && !guiSleeping) { - debugPrintln(F("GUI: Going to sleep now...")); + dispatchIdle(F("LONG")); guiSleeping = true; } return shouldSleep; @@ -90,7 +93,7 @@ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) bool shouldSleep = guiCheckSleep(); if(!shouldSleep && guiSleeping) { - debugPrintln(F("GUI: Waking up!")); + dispatchIdle(F("OFF")); guiSleeping = false; } @@ -117,10 +120,35 @@ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) return false; /*Return `false` because we are not buffering and no more data to read*/ } +void guiCalibrate() +{ + tft.fillScreen(TFT_BLACK); + tft.setCursor(20, 0); + // tft.setTextFont(2); + tft.setTextSize(1); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + + tft.println(PSTR("Touch corners as indicated")); + + tft.setTextFont(1); + tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15); + + for(uint8_t i = 0; i < 5; i++) { + Serial.print(calData[i]); + if(i < 4) Serial.print(", "); + } + + tft.setTouch(calData); + lv_obj_invalidate(lv_disp_get_layer_sys(NULL)); +} + void guiSetup(TFT_eSPI & screen, JsonObject settings) { size_t buffer_size; tft = screen; + + tft.setTouch(calData); + lv_init(); #if defined(ARDUINO_ARCH_ESP32) @@ -209,6 +237,10 @@ void guiSetup(TFT_eSPI & screen, JsonObject settings) /*Initialize the graphics library's tick*/ tick.attach_ms(guiTickPeriod, lv_tick_handler); +#if LV_USE_FS_IF != 0 + lv_fs_if_init(); +#endif + // guiLoop(); } diff --git a/src/hasp_gui.h b/src/hasp_gui.h index 4d4e4061..a3f482d2 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -9,6 +9,9 @@ void guiSetup(TFT_eSPI & screen, JsonObject settings); void guiLoop(void); void guiStop(void); + +void guiCalibrate(); + bool guiGetConfig(const JsonObject & settings); // lv_res_t guiChangeTheme(uint8_t themeid, uint16_t hue, String font, uint8_t fontsize); diff --git a/src/hasp_http.cpp b/src/hasp_http.cpp index 2feaea28..bfd23808 100644 --- a/src/hasp_http.cpp +++ b/src/hasp_http.cpp @@ -251,10 +251,10 @@ void httpHandleReboot() delay(500); debugPrintln(PSTR("HTTP: Reboot device")); - haspSetAttr(F("p[0].b[1].txt"), F("\"Rebooting...\"")); + // haspProcessAttribute(F("p[0].b[1].txt"), F("\"Rebooting...\"")); delay(500); - haspReset(); + haspReset(true); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1007,7 +1007,7 @@ void httpHandleResetConfig() if(resetConfirmed) { delay(250); // configClearSaved(); - haspReset(); + haspReset(false); // Do not save the current config } } diff --git a/src/hasp_http.h b/src/hasp_http.h index d0744928..71a96c12 100644 --- a/src/hasp_http.h +++ b/src/hasp_http.h @@ -1,6 +1,7 @@ #ifndef HASP_HTTP_H #define HASP_HTTP_H +#include #include "ArduinoJson.h" void httpSetup(const JsonObject & settings); diff --git a/src/hasp_mqtt.cpp b/src/hasp_mqtt.cpp index f8ad0f89..a65774ac 100644 --- a/src/hasp_mqtt.cpp +++ b/src/hasp_mqtt.cpp @@ -16,6 +16,7 @@ #include "hasp_config.h" #include "hasp_mqtt.h" #include "hasp_wifi.h" +#include "hasp_dispatch.h" #include "hasp.h" #ifdef USE_CONFIG_OVERRIDE @@ -71,8 +72,6 @@ std::string mqttPassword = ""; std::string mqttGroupName = "plates"; /* -const String mqttCommandSubscription = mqttCommandTopic + "/#"; -const String mqttGroupCommandSubscription = mqttGroupCommandTopic + "/#"; const String mqttLightSubscription = "hasp/" + String(haspGetNodename()) + "/light/#"; const String mqttLightBrightSubscription = "hasp/" + String(haspGetNodename()) + "/brightness/#"; */ @@ -82,87 +81,53 @@ PubSubClient mqttClient(wifiClient); //////////////////////////////////////////////////////////////////////////////////////////////////// // Send changed values OUT -void mqttSendNewEvent(uint8_t pageid, uint8_t btnid, int32_t val) + +void mqttSendState(const char * subtopic, const char * payload) { - char topic[72]; - sprintf_P(topic, PSTR("hasp/%s/state/p[%u].b[%u].event"), haspGetNodename().c_str(), pageid, btnid); - char value[32]; - itoa(val, value, 10); - mqttClient.publish(topic, value); - debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(value)); + // page = 0 + // p[0].b[0].attr = abc + // dim = 100 + // idle = 0/1 + // light = 0/1 + // brightness = 100 + + char topic[128]; + sprintf_P(topic, PSTR("%sstate/%s"), mqttNodeTopic.c_str(), subtopic); + mqttClient.publish(topic, payload); + debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(payload)); // as json - sprintf_P(topic, PSTR("hasp/%s/state/json"), haspGetNodename().c_str(), pageid, btnid); - sprintf_P(value, PSTR("{\"event\":\"p[%u]].b[%u].event\", \"value\":%u}"), pageid, btnid, val); + char value[256]; + sprintf_P(topic, PSTR("%sstate/json"), mqttNodeTopic.c_str()); + sprintf_P(value, PSTR("{\"%s\":\"%s\"}"), subtopic, payload); mqttClient.publish(topic, value); debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(value)); } +void mqttSendNewValue(uint8_t pageid, uint8_t btnid, const char * attribute, String txt) +{ + char subtopic[32]; + sprintf_P(subtopic, PSTR("p[%u].b[%u].%s"), pageid, btnid, attribute); + mqttSendState(subtopic, txt.c_str()); +} + void mqttSendNewValue(uint8_t pageid, uint8_t btnid, int32_t val) { - char topic[72]; - sprintf_P(topic, PSTR("hasp/%s/state/p[%u].b[%u].val"), haspGetNodename().c_str(), pageid, btnid); - char value[32]; + char value[16]; itoa(val, value, 10); - mqttClient.publish(topic, value); - debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(value)); - - // as json - sprintf_P(topic, PSTR("hasp/%s/state/json"), haspGetNodename().c_str(), pageid, btnid); - sprintf_P(value, PSTR("{\"event\":\"p[%u]].b[%u].val\", \"value\":%u}"), pageid, btnid, val); - mqttClient.publish(topic, value); - debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(value)); + mqttSendNewValue(pageid, btnid, "val", value); } void mqttSendNewValue(uint8_t pageid, uint8_t btnid, String txt) { - char topic[72]; - sprintf_P(topic, PSTR("hasp/%s/state/p[%u].b[%u].txt"), haspGetNodename().c_str(), pageid, btnid); - mqttClient.publish(topic, txt.c_str()); - debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + txt); - - // as json - char value[64]; - sprintf_P(topic, PSTR("hasp/%s/state/json"), haspGetNodename().c_str(), pageid, btnid); - sprintf_P(value, PSTR("{\"event\":\"p[%u]].b[%u].txt\", \"value\":\"%s\"}"), pageid, btnid, txt.c_str()); - mqttClient.publish(topic, value); - debugPrintln(String(F("MQTT OUT: ")) + String(topic) + " = " + String(value)); + mqttSendNewValue(pageid, btnid, "txt", txt); } -void mqttHandlePage(String strPageid) +void mqttSendNewEvent(uint8_t pageid, uint8_t btnid, int32_t val) { - if(strPageid.length() == 0) { - String strPayload = String(haspGetPage()); - String topic = mqttNodeTopic + F("state/page"); - char buffer[64]; - sprintf_P(buffer, PSTR("MQTT OUT: %s = %s"), topic.c_str(), strPayload.c_str()); - debugPrintln(buffer); - mqttClient.publish(topic.c_str(), strPayload.c_str()); - } else { - if(strPageid.toInt() <= 250) haspSetPage(strPageid.toInt()); - } -} - -void mqttHandleJson(String & strPayload) -{ // Parse an incoming JSON array into individual Nextion commands - if(strPayload.endsWith( - ",]")) { // Trailing null array elements are an artifact of older Home Assistant automations and need to - // be removed before parsing by ArduinoJSON 6+ - strPayload.remove(strPayload.length() - 2, 2); - strPayload.concat("]"); - } - DynamicJsonDocument nextionCommands(mqttMaxPacketSize + 1024); - DeserializationError jsonError = deserializeJson(nextionCommands, strPayload); - if(jsonError) { // Couldn't parse incoming JSON command - debugPrintln(String(F("MQTT: [ERROR] Failed to parse incoming JSON command with error: ")) + - String(jsonError.c_str())); - return; - } - - for(uint8_t i = 0; i < nextionCommands.size(); i++) { - debugPrintln(nextionCommands[i]); - // nextionSendCmd(nextionCommands[i]); - } + char value[16]; + itoa(val, value, 10); + mqttSendNewValue(pageid, btnid, "event", value); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -204,11 +169,7 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) // debugPrintln(String(F("MQTT Short Topic : '")) + strTopic + "'"); if(strTopic == F("command")) { - if(strPayload == "") { // '[...]/device/command' -m '' = No command requested, respond with mqttStatusUpdate() - // mqttStatusUpdate(); // return status JSON via MQTT - } else { // '[...]/device/command' -m 'dim=50' == nextionSendCmd("dim=50") - // nextionSendCmd(strPayload); - } + dispatchCommand(strPayload); return; } @@ -217,7 +178,7 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) // debugPrintln(String(F("MQTT Shorter Command Topic : '")) + strTopic + "'"); if(strTopic == F("page")) { // '[...]/device/command/page' -m '1' == nextionSendCmd("page 1") - mqttHandlePage(strPayload); + dispatchPage(strPayload); } else if(strTopic == F("dim")) { // '[...]/device/command/page' -m '1' == nextionSendCmd("page 1") #if defined(ARDUINO_ARCH_ESP32) ledcWrite(0, map(strPayload.toInt(), 0, 100, 0, 1023)); // ledChannel and value @@ -227,7 +188,7 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) } else if(strTopic == F("json")) { // '[...]/device/command/json' -m '["dim=5", "page 1"]' = // nextionSendCmd("dim=50"), nextionSendCmd("page 1") - mqttHandleJson(strPayload); // Send to nextionParseJson() + dispatchJson(strPayload); // Send to nextionParseJson() } else if(strTopic == F("statusupdate")) { // '[...]/device/command/statusupdate' == mqttStatusUpdate() // mqttStatusUpdate(); // return status JSON via MQTT } else if(strTopic == F("espupdate")) { // '[...]/device/command/espupdate' -m @@ -240,17 +201,18 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) } } else if(strTopic == F("reboot")) { // '[...]/device/command/reboot' == reboot microcontroller) debugPrintln(F("MQTT: Rebooting device")); - haspReset(); + haspReset(true); } else if(strTopic == F("lcdreboot")) { // '[...]/device/command/lcdreboot' == reboot LCD panel) debugPrintln(F("MQTT: Rebooting LCD")); - haspReset(); + haspReset(true); } else if(strTopic == F("factoryreset")) { // '[...]/device/command/factoryreset' == clear all saved settings) // configClearSaved(); - } else if(strPayload == "") { // '[...]/device/command/p[1].b[4].txt' -m '' == nextionGetAttr("p[1].b[4].txt") - haspProcessAttribute(strTopic, ""); + //} else if(strPayload == "") { // '[...]/device/command/p[1].b[4].txt' -m '' == + // nextionGetAttr("p[1].b[4].txt") + // haspProcessAttribute(strTopic, ""); } else { // '[...]/device/command/p[1].b[4].txt' -m '"Lights On"' == // nextionSetAttr("p[1].b[4].txt", "\"Lights On\"") - haspProcessAttribute(strTopic, strPayload); + dispatchAttribute(strTopic, strPayload); } return; } @@ -434,7 +396,7 @@ bool mqttSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_GROUP)].isNull()) { if(mqttGroupName != settings[FPSTR(F_CONFIG_GROUP)].as().c_str()) { - debugPrintln(F("mqttGroupName changed")); + debugPrintln(F("mqttGroupName set")); } changed |= mqttGroupName != settings[FPSTR(F_CONFIG_GROUP)].as().c_str(); @@ -443,7 +405,7 @@ bool mqttSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_HOST)].isNull()) { if(mqttServer != settings[FPSTR(F_CONFIG_HOST)].as().c_str()) { - debugPrintln(F("mqttServer changed")); + debugPrintln(F("mqttServer set")); } changed |= mqttServer != settings[FPSTR(F_CONFIG_HOST)].as().c_str(); @@ -452,7 +414,7 @@ bool mqttSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_PORT)].isNull()) { if(mqttPort != settings[FPSTR(F_CONFIG_PORT)].as()) { - debugPrintln(F("mqttPort changed")); + debugPrintln(F("mqttPort set")); } changed |= mqttPort != settings[FPSTR(F_CONFIG_PORT)].as(); @@ -461,7 +423,7 @@ bool mqttSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_USER)].isNull()) { if(mqttUser != settings[FPSTR(F_CONFIG_USER)].as().c_str()) { - debugPrintln(F("mqttUser changed")); + debugPrintln(F("mqttUser set")); } changed |= mqttUser != settings[FPSTR(F_CONFIG_USER)].as().c_str(); @@ -470,7 +432,7 @@ bool mqttSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_PASS)].isNull()) { if(mqttPassword != settings[FPSTR(F_CONFIG_PASS)].as().c_str()) { - debugPrintln(F("mqttPassword changed")); + debugPrintln(F("mqttPassword set")); } changed |= mqttPassword != settings[FPSTR(F_CONFIG_PASS)].as().c_str(); diff --git a/src/hasp_mqtt.h b/src/hasp_mqtt.h index e788613b..caf2cac4 100644 --- a/src/hasp_mqtt.h +++ b/src/hasp_mqtt.h @@ -8,6 +8,7 @@ void mqttLoop(bool wifiIsConnected); void mqttStop(); void mqttReconnect(); +void mqttSendState(const char * subtopic, const char * payload); void mqttSendNewEvent(uint8_t pageid, uint8_t btnid, int32_t val); void mqttSendNewValue(uint8_t pageid, uint8_t btnid, int32_t val); void mqttSendNewValue(uint8_t pageid, uint8_t btnid, String txt); diff --git a/src/hasp_tft.cpp b/src/hasp_tft.cpp index daca68a7..4533e4e6 100644 --- a/src/hasp_tft.cpp +++ b/src/hasp_tft.cpp @@ -38,25 +38,6 @@ void tftSetup(TFT_eSPI & tft, JsonObject settings) // uint16_t calData[5] = {0, 0, 0, 0, 0}; uint8_t calDataOK = 0; - // Calibrate - if(0) { - tft.fillScreen(TFT_BLACK); - tft.setCursor(20, 0); - // tft.setTextFont(2); - tft.setTextSize(1); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - - tft.println(PSTR("Touch corners as indicated")); - - tft.setTextFont(1); - tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15); - - for(uint8_t i = 0; i < 5; i++) { - Serial.print(calData[i]); - if(i < 4) Serial.print(", "); - } - } - tft.setTouch(calData); } @@ -90,9 +71,6 @@ void tftPinInfo(String pinfunction, int8_t pin) } } -void tftCalibrate() -{} - void tftShowConfig(TFT_eSPI & tft) { setup_t tftSetup; diff --git a/src/hasp_tft.h b/src/hasp_tft.h index 3766461e..567f29cf 100644 --- a/src/hasp_tft.h +++ b/src/hasp_tft.h @@ -7,6 +7,7 @@ void tftSetup(TFT_eSPI & screen, JsonObject settings); void tftLoop(void); void tftStop(void); + void tftShowConfig(TFT_eSPI & tft); #endif \ No newline at end of file diff --git a/src/hasp_wifi.cpp b/src/hasp_wifi.cpp index 974cd3f8..7fb0a834 100644 --- a/src/hasp_wifi.cpp +++ b/src/hasp_wifi.cpp @@ -216,16 +216,11 @@ bool wifiGetConfig(const JsonObject & settings) bool wifiSetConfig(const JsonObject & settings) { - /* if(!settings.isNull() && settings[FPSTR(F_CONFIG_STARTPAGE)] == haspStartPage && - settings[FPSTR(F_CONFIG_THEME)] == haspThemeId && settings[FPSTR(F_CONFIG_HUE)] == haspThemeHue && - settings[FPSTR(F_CONFIG_ZIFONT)] == haspZiFontPath && settings[FPSTR(F_CONFIG_PAGES)] == haspPagesPath) - return false; - */ bool changed = false; if(!settings[FPSTR(F_CONFIG_SSID)].isNull()) { if(wifiSsid != settings[FPSTR(F_CONFIG_SSID)].as().c_str()) { - debugPrintln(F("wifiSsid changed")); + debugPrintln(F("wifiSsid set")); } changed |= wifiSsid != settings[FPSTR(F_CONFIG_SSID)].as().c_str(); @@ -234,7 +229,7 @@ bool wifiSetConfig(const JsonObject & settings) if(!settings[FPSTR(F_CONFIG_PASS)].isNull() && settings[FPSTR(F_CONFIG_PASS)].as() != F("********")) { if(wifiPassword != settings[FPSTR(F_CONFIG_PASS)].as().c_str()) { - debugPrintln(F("wifiPassword changed")); + debugPrintln(F("wifiPassword set")); } changed |= wifiPassword != settings[FPSTR(F_CONFIG_PASS)].as().c_str();