diff --git a/docs/api.md b/docs/api.md index 5dfc889..65e42d4 100644 --- a/docs/api.md +++ b/docs/api.md @@ -192,6 +192,7 @@ Below are the properties you can utilize in the JSON object. **All keys are opti | `bar` | array of integers | Draws a bargraph. Without icon maximum 16 values, with icon 11 values. | N/A | X | X | | `line` | array of integers | Draws a linechart. Without icon maximum 16 values, with icon 11 values. | N/A | X | X | | `autoscale` | boolean | Enables or disables autoscaling for bar and linechart. | true | X | X | +| `barBC` | string or array of integers | Backgroundcolor of the bars. | 0 | X | X | | `progress` | integer | Shows a progress bar. Value can be 0-100. | -1 | X | X | | `progressC` | string or array of integers | The color of the progress bar. | -1 | X | X | | `progressBC` | string or array of integers | The color of the progress bar background. | -1 | X | X | @@ -232,7 +233,14 @@ Here's a sample JSON to present the text "Hello, AWTRIX 3!" in rainbow colors fo "duration": 10 } ``` + +### MQTT Placeholder +This feature is particularly useful for users without a full smart home system. It eliminates the need for an external system to display data, such as from an inverter wich can send its data vie MQTT. You can simply create a [AppName].json file in the CUSTOMAPP folder with your custom app JSON keys. This JSON file will be loaded upon boot, so you don't need to send it from an external source. Or you can also use it in your HTTP or MQTT API request. +The placeholders inside the `text` value enclosed in {{}} will be replaced with the payload of the specified MQTT topic. Currently, there are no options available for formatting the payload. +```json +{"text": "Solar: {{inverter/total/P_AC}} W"} +``` ### Drawing Instructions !> Please note: Depending on the number of objects, the RAM usage can be very high. This could cause freezes or reboots. diff --git a/lib/webserver/esp-fs-webserver.h b/lib/webserver/esp-fs-webserver.h index da24b22..71fd01d 100644 --- a/lib/webserver/esp-fs-webserver.h +++ b/lib/webserver/esp-fs-webserver.h @@ -143,7 +143,7 @@ class FSWebServer { // String trimmed = script; // removeWhiteSpaces(trimmed); - addOption("raw-javascript", script, true); + addOption("raw-javascript", script, true, MIN_F, MAX_F, 1.0, true); } void addDropdownList(const char *label, const char **array, size_t size); @@ -165,7 +165,7 @@ class FSWebServer // Add custom option to config webpage (type of parameter will be deduced from variable itself) template inline void addOption(const char *label, T val, bool hidden = false, - double d_min = MIN_F, double d_max = MAX_F, double step = 1.0) + double d_min = MIN_F, double d_max = MAX_F, double step = 1.0, bool replace = false) { File file = m_filesystem->open("/DoNotTouch.json", "r"); int sz = file.size() * 1.33; @@ -205,8 +205,8 @@ class FSWebServer key += numOptions; } - // If key is present in json, we don't need to create it. - if (doc.containsKey(key.c_str())) + // If key is present in json and replace is false, we don't need to create it. + if (doc.containsKey(key.c_str()) && !replace) return; // if min, max, step != from default, treat this as object in order to set other properties diff --git a/platformio.ini b/platformio.ini index 1916b3c..8d6da58 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,12 +39,12 @@ build_flags = -DULANZI -DMQTT_MAX_PACKET_SIZE=8192 -D CORE_DEBUG_LEVEL=0 - -D NDEBUG -Wno-attributes -Os -fno-exceptions lib_deps = - ${env.lib_deps} + ${env.lib_deps} + [env:awtrix2_upgrade] platform = espressif32 @@ -58,4 +58,4 @@ build_flags = -Os -fno-exceptions lib_deps = - ${env.lib_deps} \ No newline at end of file + ${env.lib_deps} diff --git a/src/Apps.cpp b/src/Apps.cpp index e10cb21..23d3697 100644 --- a/src/Apps.cpp +++ b/src/Apps.cpp @@ -131,7 +131,7 @@ void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, { // week days on bottom line wdPosY = 7; - timePosY = 6; + timePosY = 6 ; } // time @@ -299,6 +299,21 @@ void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i } #endif +String replacePlaceholders(String text) { + int start = 0; + while ((start = text.indexOf("{{", start)) != -1) { + int end = text.indexOf("}}", start); + if (end == -1) { + break; + } + String placeholder = text.substring(start + 2, end); + String topic = placeholder; + text.replace("{{" + placeholder + "}}", MQTTManager.getValueForTopic(topic)); + start = end + 2; + } + return text; +} + void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer) { // Abort if notifyFlag is set @@ -355,19 +370,20 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState bool hasIcon = ca->icon || ca->jpegDataSize > 0; - // Calculate text and available width - uint16_t textWidth = 0; - if (!ca->fragments.empty()) - { - for (const auto &fragment : ca->fragments) - { - textWidth += getTextWidth(fragment.c_str(), ca->textCase); - } - } - else +uint16_t textWidth = 0; +if (!ca->fragments.empty()) +{ + for (const auto &fragment : ca->fragments) { - textWidth = getTextWidth(ca->text.c_str(), ca->textCase); + String replacedFragment = replacePlaceholders(fragment); + textWidth += getTextWidth(replacedFragment.c_str(), ca->textCase); } +} +else +{ + String replacedText = replacePlaceholders(ca->text); + textWidth = getTextWidth(replacedText.c_str(), ca->textCase); +} uint16_t availableWidth = (hasIcon) ? 24 : 32; @@ -436,7 +452,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState if (ca->barSize > 0) { - DisplayManager.drawBarChart(x, y, ca->barData, ca->barSize, hasIcon, ca->color); + DisplayManager.drawBarChart(x, y, ca->barData, ca->barSize, hasIcon, ca->color, ca->barBG); } if (ca->lineSize > 0) @@ -531,6 +547,8 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState textX = hasIcon ? 9 : 0; } + String text =replacePlaceholders(ca->text); + if (noScrolling) { ca->repeat = -1; // Disable repeat if text is too short for scrolling @@ -540,25 +558,27 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState int16_t fragmentX = textX + ca->textOffset; for (size_t i = 0; i < ca->fragments.size(); ++i) { + String text =replacePlaceholders(ca->fragments[i]); DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, ca->blink)); - DisplayManager.printText(x + fragmentX, y + 6, ca->fragments[i].c_str(), false, ca->textCase); - fragmentX += getTextWidth(ca->fragments[i].c_str(), ca->textCase); + DisplayManager.printText(x + fragmentX, y + 6, text.c_str(), false, ca->textCase); + fragmentX += getTextWidth(text.c_str(), ca->textCase); } } else { + String text =replacePlaceholders(ca->text); if (ca->rainbow) { - DisplayManager.HSVtext(x + textX + ca->textOffset, 6 + y, ca->text.c_str(), false, ca->textCase); + DisplayManager.HSVtext(x + textX + ca->textOffset, 6 + y, text.c_str(), false, ca->textCase); } else if (ca->gradient[0] > -1 && ca->gradient[1] > -1) { - DisplayManager.GradientText(x + textX + ca->textOffset, 6 + y, ca->text.c_str(), ca->gradient[0], ca->gradient[1], false, ca->textCase); + DisplayManager.GradientText(x + textX + ca->textOffset, 6 + y, text.c_str(), ca->gradient[0], ca->gradient[1], false, ca->textCase); } else { DisplayManager.setTextColor(TextEffect(ca->color, ca->fade, ca->blink)); - DisplayManager.printText(x + textX + ca->textOffset, y + 6, ca->text.c_str(), false, ca->textCase); + DisplayManager.printText(x + textX + ca->textOffset, y + 6, text.c_str(), false, ca->textCase); } } } @@ -569,25 +589,26 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState int16_t fragmentX = ca->scrollposition + ca->textOffset; for (size_t i = 0; i < ca->fragments.size(); ++i) { + String text =replacePlaceholders(ca->fragments[i]); DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, ca->blink)); - DisplayManager.printText(x + fragmentX, y + 6, ca->fragments[i].c_str(), false, ca->textCase); - fragmentX += getTextWidth(ca->fragments[i].c_str(), ca->textCase); + DisplayManager.printText(x + fragmentX, y + 6, text.c_str(), false, ca->textCase); + fragmentX += getTextWidth(text.c_str(), ca->textCase); } } else { if (ca->rainbow) { - DisplayManager.HSVtext(x + ca->scrollposition + ca->textOffset, 6 + y, ca->text.c_str(), false, ca->textCase); + DisplayManager.HSVtext(x + ca->scrollposition + ca->textOffset, 6 + y, text.c_str(), false, ca->textCase); } else if (ca->gradient[0] > -1 && ca->gradient[1] > -1) { - DisplayManager.GradientText(x + ca->scrollposition + ca->textOffset, 6 + y, ca->text.c_str(), ca->gradient[0], ca->gradient[1], false, ca->textCase); + DisplayManager.GradientText(x + ca->scrollposition + ca->textOffset, 6 + y, text.c_str(), ca->gradient[0], ca->gradient[1], false, ca->textCase); } else { DisplayManager.setTextColor(TextEffect(ca->color, ca->fade, ca->blink)); - DisplayManager.printText(x + ca->scrollposition + ca->textOffset, 6 + y, ca->text.c_str(), false, ca->textCase); + DisplayManager.printText(x + ca->scrollposition + ca->textOffset, 6 + y, text.c_str(), false, ca->textCase); } } } diff --git a/src/Apps.h b/src/Apps.h index 263c3fa..0cbe6cf 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -33,6 +33,7 @@ struct CustomApp float iconPosition = 0; bool iconWasPushed = false; int barData[16] = {0}; + uint32_t barBG = 0; int lineData[16] = {0}; int gradient[2] = {0}; int barSize; diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 34c28ba..8ddf6cf 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -458,6 +458,26 @@ bool DisplayManager_::parseCustomPage(const String &name, const char *json, bool return true; } +// Function to subscribe to MQTT topics based on placeholders in text +void subscribeToPlaceholders(String text) +{ + int start = 0; + while ((start = text.indexOf("{{", start)) != -1) + { + int end = text.indexOf("}}", start); + if (end == -1) + { + break; + } + String placeholder = text.substring(start + 2, end); + String topic = placeholder; + + MQTTManager.subscribe(topic.c_str()); + + start = end + 2; + } +} + bool DisplayManager_::generateCustomPage(const String &name, JsonObject doc, bool preventSave) { CustomApp customApp; @@ -543,6 +563,11 @@ bool DisplayManager_::generateCustomPage(const String &name, JsonObject doc, boo if (doc.containsKey(key)) { + if (doc.containsKey("barBC")) + { + auto color = doc["barBC"]; + customApp.barBG = getColorFromJsonVariant(color, 0); + } JsonArray data = doc[key]; int index = 0; int maximum = 0; @@ -683,6 +708,13 @@ bool DisplayManager_::generateCustomPage(const String &name, JsonObject doc, boo customApp.colors.clear(); customApp.fragments.clear(); + + if (doc.containsKey("text")) + { + String text = doc["text"]; + subscribeToPlaceholders(utf8ascii(text)); + } + if (doc.containsKey("text") && doc["text"].is()) { JsonArray textArray = doc["text"].as(); @@ -847,6 +879,12 @@ bool DisplayManager_::generateNotification(uint8_t source, const char *json) if (doc.containsKey(key)) { + + if (doc.containsKey("barBC")) + { + auto color = doc["barBC"]; + newNotification.barBG = getColorFromJsonVariant(color, 0); + } JsonArray data = doc[key]; int index = 0; int maximum = 0; @@ -1445,7 +1483,7 @@ void DisplayManager_::drawMenuIndicator(int cur, int total, uint32_t color) } } -void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int newData[], byte dataSize, bool withIcon, uint32_t color) +void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint32_t color, uint32_t barBG) { int availableWidth = withIcon ? (32 - 9) : 32; int gap = 1; @@ -1456,27 +1494,30 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int newData[], by for (int i = 0; i < dataSize; i++) { int x1 = x + startX + i * (barWidth + gap); - int barHeight = newData[i]; - int y1 = (barHeight > 0) ? (8 - barHeight) : 8; + int barHeight = data[i]; - if (barHeight > 0) + if (barBG > 0) { - drawFilledRect(x1, y1 + y, barWidth, barHeight, color); + // Draw background bar + drawFilledRect(x1, y, barWidth, 8, barBG); } + + int y1 = (barHeight > 0) ? (8 - barHeight) : 8; + drawFilledRect(x1, y1 + y, barWidth, barHeight, color); } } -void DisplayManager_::drawLineChart(int16_t x, int16_t y, const int newData[], byte dataSize, bool withIcon, uint32_t color) +void DisplayManager_::drawLineChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint32_t color) { int availableWidth = withIcon ? (32 - 9) : 32; int startX = withIcon ? 9 : 0; float xStep = static_cast(availableWidth) / static_cast(dataSize - 1); int lastX = x + startX; - int lastY = y + 8 - newData[0]; + int lastY = y + 8 - data[0]; for (int i = 1; i < dataSize; i++) { int x1 = x + startX + static_cast(xStep * i); - int y1 = y + 8 - newData[i]; + int y1 = y + 8 - data[i]; drawLine(lastX, lastY, x1, y1, color); lastX = x1; lastY = y1; @@ -1949,26 +1990,28 @@ String CRGBtoHex(CRGB color) return String(buf); } -String getOverlayName() { - switch(GLOBAL_OVERLAY) { - case DRIZZLE: - return "drizzle"; - case RAIN: - return "rain"; - case SNOW: - return "snow"; - case STORM: - return "storm"; - case THUNDER: - return "thunder"; - case FROST: - return "frost"; - case NONE: - return "clear"; - default: - Serial.println(F("Invalid effect.")); - return "invalid"; // Oder einen leeren String oder einen Fehlerwert zurückgeben - } +String getOverlayName() +{ + switch (GLOBAL_OVERLAY) + { + case DRIZZLE: + return "drizzle"; + case RAIN: + return "rain"; + case SNOW: + return "snow"; + case STORM: + return "storm"; + case THUNDER: + return "thunder"; + case FROST: + return "frost"; + case NONE: + return "clear"; + default: + Serial.println(F("Invalid effect.")); + return "invalid"; // Oder einen leeren String oder einen Fehlerwert zurückgeben + } } String DisplayManager_::getSettings() @@ -2018,8 +2061,6 @@ String DisplayManager_::getSettings() return serializeJson(doc, jsonString), jsonString; } - - void DisplayManager_::setNewSettings(const char *json) { if (DEBUG_MODE) diff --git a/src/DisplayManager.h b/src/DisplayManager.h index c3ba36d..0b7391d 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -50,7 +50,7 @@ class DisplayManager_ void drawProgressBar(int16_t x, int16_t y, int progress, uint32_t pColor, uint32_t pbColor); void drawMenuIndicator(int cur, int total, uint32_t color); void drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); - void drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint32_t color); + void drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint32_t color, uint32_t barBG); void drawLineChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint32_t color); void updateAppVector(const char *json); void setMatrixLayout(int layout); diff --git a/src/Functions.cpp b/src/Functions.cpp index cd18df8..e58cc80 100644 --- a/src/Functions.cpp +++ b/src/Functions.cpp @@ -163,9 +163,35 @@ byte utf8ascii(byte ascii) break; case 0xC3: + // polish + if (ascii == 0xB3) return 0x6F; + if (ascii == 0x93) return 0x4F; + return (ascii | 0xC0); // - 34; break; + case 0xC4: + // polish + if (ascii == 0x85) return 0x61; + if (ascii == 0x84) return 0x41; + if (ascii == 0x87) return 0x63; + if (ascii == 0x86) return 0x43; + if (ascii == 0x99) return 0x65; + if (ascii == 0x98) return 0x45; + + case 0xC5: + // polish + if (ascii == 0x82) return 0x6C; + if (ascii == 0x81) return 0x4C; + if (ascii == 0x84) return 0x6E; + if (ascii == 0x83) return 0x4E; + if (ascii == 0x9A) return 0x53; + if (ascii == 0xBC) return 0x7A; + if (ascii == 0xBB) return 0x5A; + if (ascii == 0xBA) return 0x7A; + if (ascii == 0xB9) return 0x5A; + if (ascii == 0x9B) return 0x73; + case 0x82: if (ascii == 0xAC) // return (0xEA); diff --git a/src/Globals.cpp b/src/Globals.cpp index 7c60da8..5315599 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -161,7 +161,7 @@ void loadDevSettings() HOSTNAME = doc["hostname"].as(); } - if (doc.containsKey("buzzer_volume")) + if (doc.containsKey("buzzer_volume")) { BUZ_VOL = doc["buzzer_volume"].as(); } @@ -338,7 +338,7 @@ IPAddress gateway; IPAddress subnet; IPAddress primaryDNS; IPAddress secondaryDNS; -const char *VERSION = "0.96"; +const char *VERSION = "0.97"; String MQTT_HOST = ""; uint16_t MQTT_PORT = 1883; @@ -436,7 +436,7 @@ uint32_t HUM_COLOR = 0; bool ARTNET_MODE; bool MOODLIGHT_MODE; long STATS_INTERVAL = 10000; -bool DEBUG_MODE = false; +bool DEBUG_MODE = true; uint8_t MIN_BRIGHTNESS = 2; uint8_t MAX_BRIGHTNESS = 160; double movementFactor = 0.5; diff --git a/src/MQTTManager.cpp b/src/MQTTManager.cpp index c8d9fe9..0aae02c 100644 --- a/src/MQTTManager.cpp +++ b/src/MQTTManager.cpp @@ -10,6 +10,8 @@ #include "UpdateManager.h" #include "PowerManager.h" +const uint16_t PORT = 1883; + WiFiClient espClient; HADevice device; HAMqtt mqtt(espClient, device, 26); @@ -26,6 +28,8 @@ HABinarySensor *btnleft, *btnmid, *btnright = nullptr; bool connected; char matID[40], ind1ID[40], ind2ID[40], ind3ID[40], briID[40], btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40], doUpdateID[40], batID[40], myID[40], sSpeed[40], effectID[40], ipAddrID[40]; long previousMillis_Stats; +std::map mqttValues; +std::vector topicsToSubscribe; // The getter for the instantiated singleton instance MQTTManager_ &MQTTManager_::getInstance() { @@ -36,156 +40,29 @@ MQTTManager_ &MQTTManager_::getInstance() // Initialize the global shared instance MQTTManager_ &MQTTManager = MQTTManager.getInstance(); -void onButtonCommand(HAButton *sender) -{ - if (sender == dismiss) - { - DisplayManager.dismissNotify(); - } - else if (sender == nextApp) - { - DisplayManager.nextApp(); - } - else if (sender == prevApp) - { - DisplayManager.previousApp(); - } - else if (sender == doUpdate) - { - if (UpdateManager.checkUpdate(true)) - { - UpdateManager.updateFirmware(); - } - } -} - -void onSwitchCommand(bool state, HASwitch *sender) +void processMqttMessage(const String &strTopic, const String &payloadCopy) { - AUTO_TRANSITION = state; - DisplayManager.setAutoTransition(state); - saveSettings(); - sender->setState(state); -} - -void onSelectCommand(int8_t index, HASelect *sender) -{ - if (sender == BriMode) - { - switch (index) - { - case 0: - AUTO_BRIGHTNESS = false; - Matrix->setBrightness(BRIGHTNESS, true); - break; - case 1: - AUTO_BRIGHTNESS = true; - break; - } - } - else if (sender == transEffect) - { - TRANS_EFFECT = index; - } - saveSettings(); - sender->setState(index); -} - -void onRGBColorCommand(HALight::RGBColor color, HALight *sender) -{ - if (sender == Matrix) - { - TEXTCOLOR_888 = (color.red << 16) | (color.green << 8) | color.blue; - DisplayManager.setCustomAppColors(TEXTCOLOR_888); - saveSettings(); - } - else if (sender == Indikator1) - { - DisplayManager.setIndicator1Color((color.red << 16) | (color.green << 8) | color.blue); - } - else if (sender == Indikator2) - { - DisplayManager.setIndicator2Color((color.red << 16) | (color.green << 8) | color.blue); - } - else if (sender == Indikator3) - { - DisplayManager.setIndicator3Color((color.red << 16) | (color.green << 8) | color.blue); - } - sender->setRGBColor(color); // report color back to the Home Assistant -} - -void onStateCommand(bool state, HALight *sender) -{ - if (sender == Matrix) - { - DisplayManager.setPower(state); - } - else if (sender == Indikator1) - { - DisplayManager.setIndicator1State(state); - } - else if (sender == Indikator2) - { - DisplayManager.setIndicator2State(state); - } - else if (sender == Indikator3) - { - DisplayManager.setIndicator3State(state); - } - sender->setState(state); -} - -void onBrightnessCommand(uint8_t brightness, HALight *sender) -{ - sender->setBrightness(brightness); - if (AUTO_BRIGHTNESS) - return; - BRIGHTNESS = brightness; - saveSettings(); - DisplayManager.setBrightness(brightness); -} - -void onNumberCommand(HANumeric number, HANumber *sender) -{ - if (!number.isSet()) - { - // the reset command was send by Home Assistant - } - else + if (DEBUG_MODE) { - SCROLL_SPEED = number.toInt8(); - saveSettings(); + DEBUG_PRINTF("Processing MQTT message for topic %s", strTopic.c_str()); + DEBUG_PRINTF("Payload: %s", payloadCopy.c_str()); } - sender->setState(number); // report the selected option back to the HA panel -} - -void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) -{ - if (DEBUG_MODE) - DEBUG_PRINTF("MQTT message received at topic %s", topic); - String strTopic = String(topic); - char *payloadCopy = new char[length + 1]; - memcpy(payloadCopy, payload, length); - payloadCopy[length] = '\0'; - if (DEBUG_MODE) - DEBUG_PRINTF("Payload: %s", payloadCopy); ++RECEIVED_MESSAGES; + if (strTopic.equals(MQTT_PREFIX + "/notify")) { - if (payload[0] != '{' || payload[length - 1] != '}') + if (payloadCopy[0] != '{' || payloadCopy[payloadCopy.length() - 1] != '}') { - delete[] payloadCopy; return; } - DisplayManager.generateNotification(0, payloadCopy); - delete[] payloadCopy; + DisplayManager.generateNotification(0, payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/notify/dismiss")) { DisplayManager.dismissNotify(); - delete[] payloadCopy; return; } @@ -195,80 +72,61 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) { UpdateManager.updateFirmware(); } - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/apps")) { - DisplayManager.updateAppVector(payloadCopy); - delete[] payloadCopy; + DisplayManager.updateAppVector(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/switch")) { - DisplayManager.switchToApp(payloadCopy); - delete[] payloadCopy; + DisplayManager.switchToApp(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/sendscreen")) { MQTTManager.getInstance().publish("screen", DisplayManager.ledsAsJson().c_str()); - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/settings")) { - DisplayManager.setNewSettings(payloadCopy); - delete[] payloadCopy; + DisplayManager.setNewSettings(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/r2d2")) { - PeripheryManager.r2d2(payloadCopy); - delete[] payloadCopy; + PeripheryManager.r2d2(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/nextapp")) { DisplayManager.nextApp(); - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/previousapp")) { DisplayManager.previousApp(); - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/rtttl")) { - PeripheryManager.playRTTTLString(payloadCopy); - delete[] payloadCopy; - return; - } - - if (strTopic.equals(MQTT_PREFIX + "/doupdate")) - { - if (UpdateManager.checkUpdate(true)) - { - UpdateManager.updateFirmware(); - } - delete[] payloadCopy; + PeripheryManager.playRTTTLString(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/power")) { StaticJsonDocument<128> doc; - DeserializationError error = deserializeJson(doc, payload); + DeserializationError error = deserializeJson(doc, payloadCopy.c_str()); if (error) { if (DEBUG_MODE) @@ -279,15 +137,13 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) { DisplayManager.setPower(doc["power"].as()); } - - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/sleep")) { StaticJsonDocument<128> doc; - DeserializationError error = deserializeJson(doc, payload); + DeserializationError error = deserializeJson(doc, payloadCopy.c_str()); if (error) { if (DEBUG_MODE) @@ -299,73 +155,229 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) DisplayManager.setPower(false); PowerManager.sleep(doc["sleep"].as()); } - - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/indicator1")) { - DisplayManager.indicatorParser(1, payloadCopy); - delete[] payloadCopy; + DisplayManager.indicatorParser(1, payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/indicator2")) { - DisplayManager.indicatorParser(2, payloadCopy); - delete[] payloadCopy; + DisplayManager.indicatorParser(2, payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/indicator3")) { - DisplayManager.indicatorParser(3, payloadCopy); - delete[] payloadCopy; + DisplayManager.indicatorParser(3, payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/moodlight")) { - DisplayManager.moodlight(payloadCopy); - delete[] payloadCopy; + DisplayManager.moodlight(payloadCopy.c_str()); return; } if (strTopic.equals(MQTT_PREFIX + "/reboot")) { if (DEBUG_MODE) - DEBUG_PRINTLN("REBOOT COMMAND RECEIVED") + DEBUG_PRINTLN("REBOOT COMMAND RECEIVED"); delay(1000); ESP.restart(); - delete[] payloadCopy; return; } if (strTopic.equals(MQTT_PREFIX + "/sound")) { - PeripheryManager.parseSound(payloadCopy); - delete[] payloadCopy; + PeripheryManager.parseSound(payloadCopy.c_str()); return; } if (strTopic.startsWith(MQTT_PREFIX + "/custom")) { - String topic_str = topic; + String topic_str = strTopic; String prefix = MQTT_PREFIX + "/custom/"; if (topic_str.startsWith(prefix)) { topic_str = topic_str.substring(prefix.length()); - DisplayManager.parseCustomPage(topic_str, payloadCopy, false); + DisplayManager.parseCustomPage(topic_str, payloadCopy.c_str(), false); + } + return; + } + + if (mqttValues.find(strTopic) != mqttValues.end()) + { + mqttValues[strTopic] = payloadCopy; + if (DEBUG_MODE) + { + Serial.print("Updated existing topic: "); + Serial.println(strTopic); + Serial.print("New value: "); + Serial.println(mqttValues[strTopic]); + } + return; + } +} + +void onButtonCommand(HAButton *sender) +{ + if (sender == dismiss) + { + DisplayManager.dismissNotify(); + } + else if (sender == nextApp) + { + DisplayManager.nextApp(); + } + else if (sender == prevApp) + { + DisplayManager.previousApp(); + } + else if (sender == doUpdate) + { + if (UpdateManager.checkUpdate(true)) + { + UpdateManager.updateFirmware(); + } + } +} + +void onSwitchCommand(bool state, HASwitch *sender) +{ + AUTO_TRANSITION = state; + DisplayManager.setAutoTransition(state); + saveSettings(); + sender->setState(state); +} + +void onSelectCommand(int8_t index, HASelect *sender) +{ + if (sender == BriMode) + { + switch (index) + { + case 0: + AUTO_BRIGHTNESS = false; + Matrix->setBrightness(BRIGHTNESS, true); + break; + case 1: + AUTO_BRIGHTNESS = true; + break; } + } + else if (sender == transEffect) + { + TRANS_EFFECT = index; + } + saveSettings(); + sender->setState(index); +} - delete[] payloadCopy; +void onRGBColorCommand(HALight::RGBColor color, HALight *sender) +{ + if (sender == Matrix) + { + TEXTCOLOR_888 = (color.red << 16) | (color.green << 8) | color.blue; + DisplayManager.setCustomAppColors(TEXTCOLOR_888); + saveSettings(); + } + else if (sender == Indikator1) + { + DisplayManager.setIndicator1Color((color.red << 16) | (color.green << 8) | color.blue); + } + else if (sender == Indikator2) + { + DisplayManager.setIndicator2Color((color.red << 16) | (color.green << 8) | color.blue); + } + else if (sender == Indikator3) + { + DisplayManager.setIndicator3Color((color.red << 16) | (color.green << 8) | color.blue); + } + sender->setRGBColor(color); // report color back to the Home Assistant +} + +void onStateCommand(bool state, HALight *sender) +{ + if (sender == Matrix) + { + DisplayManager.setPower(state); + } + else if (sender == Indikator1) + { + DisplayManager.setIndicator1State(state); + } + else if (sender == Indikator2) + { + DisplayManager.setIndicator2State(state); + } + else if (sender == Indikator3) + { + DisplayManager.setIndicator3State(state); + } + sender->setState(state); +} + +void onBrightnessCommand(uint8_t brightness, HALight *sender) +{ + sender->setBrightness(brightness); + if (AUTO_BRIGHTNESS) return; + BRIGHTNESS = brightness; + saveSettings(); + DisplayManager.setBrightness(brightness); +} + +void onNumberCommand(HANumeric number, HANumber *sender) +{ + if (!number.isSet()) + { + // the reset command was send by Home Assistant + } + else + { + SCROLL_SPEED = number.toInt8(); + saveSettings(); + } + + sender->setState(number); // report the selected option back to the HA panel +} + +void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) +{ + if (DEBUG_MODE) + DEBUG_PRINTF("MQTT message received at topic %s", topic); + + // Create a copy of the payload + char *payloadCopy = new char[length + 1]; + memcpy(payloadCopy, payload, length); + payloadCopy[length] = '\0'; + + // Convert to String and handle the message + processMqttMessage(String(topic), String(payloadCopy)); + + // Clean up the payload copy + delete[] payloadCopy; +} + +String MQTTManager_::getValueForTopic(const String &topic) +{ + if (mqttValues.find(topic) != mqttValues.end()) + { + return mqttValues[topic]; + } + else + { + return "N/A"; // Return "N/A" if the topic is not found } } void onMqttConnected() { + if (DEBUG_MODE) DEBUG_PRINTLN(F("MQTT Connected")); const char *topics[] PROGMEM = { @@ -400,17 +412,42 @@ void onMqttConnected() mqtt.subscribe((MQTT_PREFIX + topic).c_str()); delay(30); } + + for (const auto &topic : topicsToSubscribe) + { + mqtt.subscribe(topic.c_str()); + if (DEBUG_MODE) + Serial.printf("Subscribed to topic %s\n", topic.c_str()); + } + delay(200); if (HA_DISCOVERY) { myOwnID->setValue(MQTT_PREFIX.c_str()); version->setValue(VERSION); } + MQTTManager.publish("stats/effects", DisplayManager.getEffectNames().c_str()); MQTTManager.publish("stats/transitions", DisplayManager.getTransitionNames().c_str()); + // MQTTManager.publish("stats/device", "online"); + connected = true; } +bool MQTTManager_::subscribe(const char *topic) +{ + mqttValues[topic] = "N/A"; + if (mqtt.isConnected()) + { + mqtt.subscribe(topic); + } + else + { + topicsToSubscribe.push_back(topic); + } + return true; +} + bool MQTTManager_::isConnected() { if (MQTT_HOST != "") @@ -425,9 +462,14 @@ bool MQTTManager_::isConnected() void connect() { + mqtt.onMessage(onMqttMessage); mqtt.onConnected(onMqttConnected); + //char topic[50]; + //snprintf(topic, sizeof(topic), "%s/stats/device", MQTT_PREFIX.c_str()); // .c_str() hinzugefügt + //mqtt.setLastWill(topic, "offline", false); // "offline" statt 0 + if (MQTT_USER == "" || MQTT_PASS == "") { if (DEBUG_MODE) @@ -444,57 +486,54 @@ void connect() void MQTTManager_::sendStats() { - if (mqtt.isConnected()) + + if (HA_DISCOVERY && mqtt.isConnected()) { - if (HA_DISCOVERY && mqtt.isConnected()) - { - char buffer[8]; + char buffer[8]; #ifndef awtrix2_upgrade - snprintf(buffer, 5, "%d", BATTERY_PERCENT); - battery->setValue(buffer); + snprintf(buffer, 5, "%d", BATTERY_PERCENT); + battery->setValue(buffer); #endif - - if (SENSOR_READING) - { - snprintf(buffer, sizeof(buffer), "%.*f", TEMP_DECIMAL_PLACES, CURRENT_TEMP); - temperature->setValue(buffer); - snprintf(buffer, 5, "%.0f", CURRENT_HUM); - humidity->setValue(buffer); - } - - snprintf(buffer, 5, "%.0f", CURRENT_LUX); - illuminance->setValue(buffer); - BriMode->setState(AUTO_BRIGHTNESS, false); - Matrix->setBrightness(BRIGHTNESS); - Matrix->setState(!MATRIX_OFF, false); - HALight::RGBColor color; - color.isSet = true; - color.red = (TEXTCOLOR_888 >> 16) & 0xFF; - color.green = (TEXTCOLOR_888 >> 8) & 0xFF; - color.blue = TEXTCOLOR_888 & 0xFF; - Matrix->setRGBColor(color); - int8_t rssiValue = WiFi.RSSI(); - char rssiString[4]; - snprintf(rssiString, sizeof(rssiString), "%d", rssiValue); - strength->setValue(rssiString); - - char rambuffer[10]; - int freeHeapBytes = ESP.getFreeHeap(); - itoa(freeHeapBytes, rambuffer, 10); - ram->setValue(rambuffer); - char uptimeStr[25]; // Buffer for string representation - sprintf(uptimeStr, "%ld", PeripheryManager.readUptime()); - uptime->setValue(uptimeStr); - transition->setState(AUTO_TRANSITION, false); - ipAddr->setValue(ServerManager.myIP.toString().c_str()); + if (SENSOR_READING) + { + snprintf(buffer, sizeof(buffer), "%.*f", TEMP_DECIMAL_PLACES, CURRENT_TEMP); + temperature->setValue(buffer); + snprintf(buffer, 5, "%.0f", CURRENT_HUM); + humidity->setValue(buffer); } - publish(StatsTopic, DisplayManager.getStats().c_str()); - } + snprintf(buffer, 5, "%.0f", CURRENT_LUX); + illuminance->setValue(buffer); + BriMode->setState(AUTO_BRIGHTNESS, false); + Matrix->setBrightness(BRIGHTNESS); + Matrix->setState(!MATRIX_OFF, false); + HALight::RGBColor color; + color.isSet = true; + color.red = (TEXTCOLOR_888 >> 16) & 0xFF; + color.green = (TEXTCOLOR_888 >> 8) & 0xFF; + color.blue = TEXTCOLOR_888 & 0xFF; + Matrix->setRGBColor(color); + int8_t rssiValue = WiFi.RSSI(); + char rssiString[4]; + snprintf(rssiString, sizeof(rssiString), "%d", rssiValue); + strength->setValue(rssiString); + + char rambuffer[10]; + int freeHeapBytes = ESP.getFreeHeap(); + itoa(freeHeapBytes, rambuffer, 10); + ram->setValue(rambuffer); + char uptimeStr[25]; // Buffer for string representation + sprintf(uptimeStr, "%ld", PeripheryManager.readUptime()); + uptime->setValue(uptimeStr); + transition->setState(AUTO_TRANSITION, false); + ipAddr->setValue(ServerManager.myIP.toString().c_str()); + } + publish(StatsTopic, DisplayManager.getStats().c_str()); } void MQTTManager_::setup() { + if (HA_DISCOVERY) { if (DEBUG_MODE) @@ -689,6 +728,7 @@ void MQTTManager_::setup() Serial.println(F("Homeassistant discovery disabled")); mqtt.disableHA(); } + connect(); } @@ -697,23 +737,25 @@ void MQTTManager_::tick() if (MQTT_HOST != "") { mqtt.loop(); - unsigned long currentMillis_Stats = millis(); - if ((currentMillis_Stats - previousMillis_Stats >= STATS_INTERVAL) && (SENSORS_STABLE)) - { - previousMillis_Stats = currentMillis_Stats; - sendStats(); - } + } + unsigned long currentMillis_Stats = millis(); + if ((currentMillis_Stats - previousMillis_Stats >= STATS_INTERVAL) && (SENSORS_STABLE)) + { + previousMillis_Stats = currentMillis_Stats; + sendStats(); } } void MQTTManager_::publish(const char *topic, const char *payload) { - if (!mqtt.isConnected()) - return; char result[100]; strcpy(result, MQTT_PREFIX.c_str()); strcat(result, "/"); strcat(result, topic); + + if (!mqtt.isConnected()) + return; + mqtt.publish(result, payload, false); } diff --git a/src/MQTTManager.h b/src/MQTTManager.h index 87ac413..4ac9c4f 100644 --- a/src/MQTTManager.h +++ b/src/MQTTManager.h @@ -2,6 +2,7 @@ #define MQTTManager_h #include +#include class MQTTManager_ { @@ -22,7 +23,9 @@ class MQTTManager_ void beginPublish(const char *topic, unsigned int plength, boolean retained); void writePayload(const char *data, const uint16_t length); void endPublish(); + bool subscribe(const char* topic); bool isConnected(); + String getValueForTopic(const String &topic); }; extern MQTTManager_ &MQTTManager; diff --git a/src/Overlays.cpp b/src/Overlays.cpp index 6265931..c95d239 100644 --- a/src/Overlays.cpp +++ b/src/Overlays.cpp @@ -176,7 +176,7 @@ void NotifyOverlay(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPl if (notifications[0].barSize > 0) { - DisplayManager.drawBarChart(0, 0, notifications[0].barData, notifications[0].barSize, hasIcon, notifications[0].color); + DisplayManager.drawBarChart(0, 0, notifications[0].barData, notifications[0].barSize, hasIcon, notifications[0].color, notifications[0].barBG); } if (notifications[0].lineSize > 0) diff --git a/src/Overlays.h b/src/Overlays.h index fea85d6..cf006e0 100644 --- a/src/Overlays.h +++ b/src/Overlays.h @@ -32,6 +32,7 @@ struct Notification int barData[16] = {0}; int lineData[16] = {0}; int barSize; + uint32_t barBG = 0; int lineSize; std::vector colors; std::vector fragments; diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index a1691d6..d5b924a 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -318,6 +318,7 @@ void ServerManager_::loadSettings() MQTT_USER = doc["Username"].as(); MQTT_PASS = doc["Password"].as(); MQTT_PREFIX = doc["Prefix"].as(); + MQTT_PREFIX.trim(); NET_STATIC = doc["Static IP"]; HA_DISCOVERY = doc["Homeassistant Discovery"]; NET_IP = doc["Local IP"].as(); diff --git a/src/htmls.h b/src/htmls.h index ff8ac7b..31a3eeb 100644 --- a/src/htmls.h +++ b/src/htmls.h @@ -63,7 +63,7 @@ static const char custom_css[] PROGMEM = R"EOF( )EOF"; static const char custom_script[] PROGMEM = R"EOF( -(function(_0x5ebe6f,_0x40f30b){var _0x4087a8=_0x4bf0,_0x4590f6=_0x5ebe6f();while(!![]){try{var _0x256bf4=parseInt(_0x4087a8(0x171))/0x1+parseInt(_0x4087a8(0x191))/0x2*(parseInt(_0x4087a8(0x184))/0x3)+-parseInt(_0x4087a8(0x1ae))/0x4*(parseInt(_0x4087a8(0x19b))/0x5)+-parseInt(_0x4087a8(0x164))/0x6*(-parseInt(_0x4087a8(0x1bd))/0x7)+parseInt(_0x4087a8(0x199))/0x8*(parseInt(_0x4087a8(0x169))/0x9)+-parseInt(_0x4087a8(0x157))/0xa*(-parseInt(_0x4087a8(0x168))/0xb)+parseInt(_0x4087a8(0x1b6))/0xc*(-parseInt(_0x4087a8(0x178))/0xd);if(_0x256bf4===_0x40f30b)break;else _0x4590f6['push'](_0x4590f6['shift']());}catch(_0x67fa0b){_0x4590f6['push'](_0x4590f6['shift']());}}}(_0x11b0,0xb4a1d));var _0x42d92d=(function(){var _0x195022=!![];return function(_0x11fb8b,_0x1dae9b){var _0x5de705=_0x195022?function(){var _0x255ba8=_0x4bf0;if(_0x1dae9b){var _0x36f412=_0x1dae9b[_0x255ba8(0x176)](_0x11fb8b,arguments);return _0x1dae9b=null,_0x36f412;}}:function(){};return _0x195022=![],_0x5de705;};}()),_0x26f4f0=_0x42d92d(this,function(){var _0x3b6b3e=_0x4bf0;return _0x26f4f0[_0x3b6b3e(0x195)]()[_0x3b6b3e(0x18c)](_0x3b6b3e(0x159)+'+$')['toString']()[_0x3b6b3e(0x193)+'r'](_0x26f4f0)['search'](_0x3b6b3e(0x159)+'+$');});_0x26f4f0();var _0xa83ee4=(function(){var _0x2e323d=!![];return function(_0x333c3a,_0x55c667){var _0x3fb2ef=_0x2e323d?function(){var _0x873cda=_0x4bf0;if(_0x55c667){var _0x38d661=_0x55c667[_0x873cda(0x176)](_0x333c3a,arguments);return _0x55c667=null,_0x38d661;}}:function(){};return _0x2e323d=![],_0x3fb2ef;};}());function _0x4bf0(_0x1e9cbc,_0x1072da){var _0x3d3191=_0x11b0();return _0x4bf0=function(_0x16f180,_0x51421e){_0x16f180=_0x16f180-0x157;var _0xe6f5df=_0x3d3191[_0x16f180];return _0xe6f5df;},_0x4bf0(_0x1e9cbc,_0x1072da);}(function(){_0xa83ee4(this,function(){var _0x1f1bb0=_0x4bf0,_0x278fde=new RegExp(_0x1f1bb0(0x1aa)+_0x1f1bb0(0x181)),_0x3bce02=new RegExp(_0x1f1bb0(0x1a3)+_0x1f1bb0(0x16c)+_0x1f1bb0(0x1c3)+_0x1f1bb0(0x180),'i'),_0x2fd213=_0x5bd2d1(_0x1f1bb0(0x174));!_0x278fde[_0x1f1bb0(0x1a7)](_0x2fd213+_0x1f1bb0(0x18b))||!_0x3bce02[_0x1f1bb0(0x1a7)](_0x2fd213+'input')?_0x2fd213('0'):_0x5bd2d1();})();}());function _0x11b0(){var _0x351fc2=['/apps/icon','test','console','\x20doesnt\x20ex','function\x20*','rn\x20this\x22)(','value','gger','548soShUM','https://co','This\x20ID','content-ty','orcer.de/i','https://aw','innerHTML','eforcer.de','13477308bUzQLV','pps/icon_t','lametric-i','Finish','Icon\x20sa','ist','metric.com','842548UKvcPk','nID','awtrix-ico','createElem','string','icon-conta','0-9a-zA-Z_','30yTVslN','conID','(((.+)+)+)','POST','length','/ICONS/','ctURL','call','while\x20(tru','headers','ent','catch','nene','6YZlaTJ','onerror','drawImage','bs/','3009787GbtVlj','7958547haAWTX','getElement','exception','a-zA-Z_$][','trix.bluef','onload','image/jpeg','createObje','973210vikrZa','width','awtrix.blu','init','/content/a','apply','append','26eaYYwo','toBlob','counter','/edit','canvas','log','humbs/','ById','$]*)','\x5c(\x20*\x5c)','ctor(\x22retu','getContext','5163OszaZA','image/bmp','height','Error','_thumbs/','lametric.c','warn','chain','search','veloper.la','ved','revokeObje','debu','362zcIVFk','img','constructo','/?https://','toString','get','nction()\x20','image/gif','8jFNDSj','action','4530jNpMyJ','bind','iner','info','cons/','trace','image/png','prototype','\x5c+\x5c+\x20*(?:[','src','rsproxy.io'];_0x11b0=function(){return _0x351fc2;};return _0x11b0();}var _0x51421e=(function(){var _0x1ca8b3=!![];return function(_0x33fffa,_0x77376d){var _0x783973=_0x1ca8b3?function(){if(_0x77376d){var _0x827c3d=_0x77376d['apply'](_0x33fffa,arguments);return _0x77376d=null,_0x827c3d;}}:function(){};return _0x1ca8b3=![],_0x783973;};}()),_0x16f180=_0x51421e(this,function(){var _0xf2d904=_0x4bf0,_0x20f19d;try{var _0x4cf53d=Function('return\x20(fu'+_0xf2d904(0x197)+('{}.constru'+_0xf2d904(0x182)+_0xf2d904(0x1ab)+'\x20)')+');');_0x20f19d=_0x4cf53d();}catch(_0x52acb3){_0x20f19d=window;}var _0x2b5208=_0x20f19d[_0xf2d904(0x1a8)]=_0x20f19d[_0xf2d904(0x1a8)]||{},_0x2ade99=[_0xf2d904(0x17d),_0xf2d904(0x18a),_0xf2d904(0x19e),'error',_0xf2d904(0x16b),'table',_0xf2d904(0x1a0)];for(var _0x4164b2=0x0;_0x4164b2<_0x2ade99[_0xf2d904(0x15b)];_0x4164b2++){var _0x5b1890=_0x51421e[_0xf2d904(0x193)+'r'][_0xf2d904(0x1a2)][_0xf2d904(0x19c)](_0x51421e),_0x2e3540=_0x2ade99[_0x4164b2],_0x37b368=_0x2b5208[_0x2e3540]||_0x5b1890;_0x5b1890['__proto__']=_0x51421e[_0xf2d904(0x19c)](_0x51421e),_0x5b1890[_0xf2d904(0x195)]=_0x37b368[_0xf2d904(0x195)][_0xf2d904(0x19c)](_0x37b368),_0x2b5208[_0x2e3540]=_0x5b1890;}});_0x16f180();function createLametricLink(){var _0x42c301=_0x4bf0,_0x5572ca=document[_0x42c301(0x16a)+_0x42c301(0x17f)](_0x42c301(0x1b8)+_0x42c301(0x158))[_0x42c301(0x1ac)],_0x36715f=document[_0x42c301(0x1c0)+'ent'](_0x42c301(0x192));_0x36715f['onerror']=function(){var _0x1563a7=_0x4bf0;openModalMessage(_0x1563a7(0x187),_0x1563a7(0x1b0)+_0x1563a7(0x1a9)+_0x1563a7(0x1bb));},_0x36715f[_0x42c301(0x1a4)]='https://de'+_0x42c301(0x18d)+_0x42c301(0x1bc)+_0x42c301(0x175)+_0x42c301(0x1b7)+_0x42c301(0x17e)+_0x5572ca;var _0xad74c9=document['getElement'+_0x42c301(0x17f)]('icon-conta'+_0x42c301(0x19d));_0xad74c9[_0x42c301(0x1b4)]='',_0xad74c9['appendChil'+'d'](_0x36715f);}function createAwtrixLink(){var _0x3432b2=_0x4bf0,_0x1564a5=document['getElement'+_0x3432b2(0x17f)](_0x3432b2(0x1bf)+'nID')[_0x3432b2(0x1ac)],_0x38f591=document[_0x3432b2(0x1c0)+_0x3432b2(0x161)]('img');_0x38f591[_0x3432b2(0x165)]=function(){var _0x13444c=_0x4bf0;openModalMessage(_0x13444c(0x187),_0x13444c(0x1b0)+'\x20doesnt\x20ex'+_0x13444c(0x1bb));},_0x38f591[_0x3432b2(0x1a4)]=_0x3432b2(0x1b3)+_0x3432b2(0x16d)+_0x3432b2(0x1b2)+_0x3432b2(0x19f)+_0x1564a5;var _0x2423a3=document[_0x3432b2(0x16a)+_0x3432b2(0x17f)](_0x3432b2(0x1c2)+_0x3432b2(0x19d));_0x2423a3[_0x3432b2(0x1b4)]='',_0x2423a3['appendChil'+'d'](_0x38f591);}async function downloadLametricImage(){var _0x13bef5=_0x4bf0,_0x293c55=document[_0x13bef5(0x16a)+_0x13bef5(0x17f)]('lametric-i'+_0x13bef5(0x158))['value'];try{let _0x17c5ec=await fetch(_0x13bef5(0x1af)+_0x13bef5(0x1a5)+_0x13bef5(0x194)+'developer.'+_0x13bef5(0x189)+'om/content'+_0x13bef5(0x1a6)+_0x13bef5(0x188)+_0x293c55),_0x377fcc=await _0x17c5ec['blob']();var _0x30f17d='';if(_0x13bef5(0x1a1)===_0x17c5ec[_0x13bef5(0x160)][_0x13bef5(0x196)](_0x13bef5(0x1b1)+'pe')){_0x30f17d='.jpg';let _0x435948=new Image(),_0x198ee8=URL['createObje'+_0x13bef5(0x15d)](_0x377fcc);_0x435948[_0x13bef5(0x16e)]=function(){var _0x2e8fd1=_0x4bf0;let _0x1c56a2=document[_0x2e8fd1(0x1c0)+_0x2e8fd1(0x161)](_0x2e8fd1(0x17c));_0x1c56a2['width']=_0x435948['width'],_0x1c56a2[_0x2e8fd1(0x186)]=_0x435948[_0x2e8fd1(0x186)];let _0x5ef64a=_0x1c56a2['getContext']('2d');_0x5ef64a[_0x2e8fd1(0x166)](_0x435948,0x0,0x0,_0x435948[_0x2e8fd1(0x172)],_0x435948[_0x2e8fd1(0x186)]),_0x1c56a2[_0x2e8fd1(0x179)](function(_0x17cebc){sendBlob(_0x17cebc,_0x293c55,_0x30f17d);},_0x2e8fd1(0x16f),0x1),URL[_0x2e8fd1(0x18f)+'ctURL'](_0x198ee8);},_0x435948[_0x13bef5(0x1a4)]=_0x198ee8;}else _0x13bef5(0x198)===_0x17c5ec[_0x13bef5(0x160)][_0x13bef5(0x196)](_0x13bef5(0x1b1)+'pe')&&(_0x30f17d='.gif',sendBlob(_0x377fcc,_0x293c55,_0x30f17d));}catch(_0x238ea7){console[_0x13bef5(0x17d)](_0x13bef5(0x163)),openModalMessage(_0x13bef5(0x187),_0x13bef5(0x1b0)+_0x13bef5(0x1a9)+'ist');}}async function downloadAwtrixImage(){var _0x526635=_0x4bf0,_0x3c8044=document['getElement'+_0x526635(0x17f)]('awtrix-ico'+_0x526635(0x1be))['value'];try{let _0xa586ba=await fetch(_0x526635(0x1af)+'rsproxy.io'+_0x526635(0x194)+_0x526635(0x173)+_0x526635(0x1b5)+'/icon_thum'+_0x526635(0x167)+_0x3c8044),_0x37e327=await _0xa586ba['blob']();var _0x26d5b3='';if(_0x526635(0x185)===_0xa586ba[_0x526635(0x160)][_0x526635(0x196)](_0x526635(0x1b1)+'pe')){_0x26d5b3='.jpg';let _0x570aca=new Image(),_0xedd9e6=URL[_0x526635(0x170)+_0x526635(0x15d)](_0x37e327);_0x570aca[_0x526635(0x16e)]=function(){var _0x397aee=_0x4bf0;let _0x272e7b=document[_0x397aee(0x1c0)+_0x397aee(0x161)]('canvas');_0x272e7b['width']=_0x570aca[_0x397aee(0x172)],_0x272e7b[_0x397aee(0x186)]=_0x570aca[_0x397aee(0x186)];let _0x39ef4c=_0x272e7b[_0x397aee(0x183)]('2d');_0x39ef4c[_0x397aee(0x166)](_0x570aca,0x0,0x0,_0x570aca[_0x397aee(0x172)],_0x570aca[_0x397aee(0x186)]),_0x272e7b[_0x397aee(0x179)](function(_0x327c4e){sendBlob(_0x327c4e,_0x3c8044,_0x26d5b3);},'image/jpeg',0x1),URL[_0x397aee(0x18f)+_0x397aee(0x15d)](_0xedd9e6);},_0x570aca[_0x526635(0x1a4)]=_0xedd9e6;}else _0x526635(0x198)===_0xa586ba[_0x526635(0x160)][_0x526635(0x196)](_0x526635(0x1b1)+'pe')&&(_0x26d5b3='.gif',sendBlob(_0x37e327,_0x3c8044,_0x26d5b3));}catch(_0x11f9e6){openModalMessage(_0x526635(0x187),'This\x20ID'+_0x526635(0x1a9)+_0x526635(0x1bb));}}function sendBlob(_0x431bbb,_0xdf5ce3,_0xf4a2ac){var _0x41ee79=_0x4bf0,_0x1bbf43=new FormData();_0x1bbf43[_0x41ee79(0x177)]('image',_0x431bbb,_0x41ee79(0x15c)+_0xdf5ce3+_0xf4a2ac),fetch(_0x41ee79(0x17b),{'method':_0x41ee79(0x15a),'body':_0x1bbf43,'mode':'no-cors'})['then'](_0x440d69=>{var _0x4e8d73=_0x4bf0;_0x440d69['ok']&&openModalMessage(_0x4e8d73(0x1b9),_0x4e8d73(0x1ba)+_0x4e8d73(0x18e));})[_0x41ee79(0x162)](_0x123299=>{console['log'](_0x123299);});}function _0x5bd2d1(_0x17c1f0){function _0x5736d9(_0xb1a345){var _0x1f8029=_0x4bf0;if(typeof _0xb1a345===_0x1f8029(0x1c1))return function(_0x55c85f){}['constructo'+'r'](_0x1f8029(0x15f)+'e)\x20{}')[_0x1f8029(0x176)](_0x1f8029(0x17a));else(''+_0xb1a345/_0xb1a345)[_0x1f8029(0x15b)]!==0x1||_0xb1a345%0x14===0x0?function(){return!![];}['constructo'+'r'](_0x1f8029(0x190)+_0x1f8029(0x1ad))[_0x1f8029(0x15e)](_0x1f8029(0x19a)):function(){return![];}['constructo'+'r'](_0x1f8029(0x190)+_0x1f8029(0x1ad))[_0x1f8029(0x176)]('stateObjec'+'t');_0x5736d9(++_0xb1a345);}try{if(_0x17c1f0)return _0x5736d9;else _0x5736d9(0x0);}catch(_0xd50873){}} +function createLametricLink(){const e=document.getElementById("lametric-iconID").value,t=document.createElement("img");t.onerror=function(){openModalMessage("Error","This ID doesnt exist")},t.src="https://developer.lametric.com/content/apps/icon_thumbs/"+e;const n=document.getElementById("icon-container");n.innerHTML="",n.appendChild(t)}async function downloadLametricImage(){const e=document.getElementById("lametric-iconID").value;try{let n=await fetch("https://developer.lametric.com/content/apps/icon_thumbs/"+e),o=await n.blob();var t="";const c=n.headers.get("content-type");if("image/jpeg"===c||"image/png"===c){t=".jpg";let n=new Image,c=URL.createObjectURL(o);n.onload=function(){let o=document.createElement("canvas");o.width=n.width,o.height=n.height,o.getContext("2d").drawImage(n,0,0,n.width,n.height),o.toBlob((function(n){sendBlob(n,e,t)}),"image/jpeg",1),URL.revokeObjectURL(c)},n.src=c}else"image/gif"===n.headers.get("content-type")&&sendBlob(o,e,t=".gif")}catch(e){console.log("Error"),openModalMessage("Error","This ID doesnt exist")}}function sendBlob(e,t,n){const o=new FormData;o.append("image",e,"ICONS/"+t+n),fetch("/edit",{method:"POST",body:o,mode:"no-cors"}).then((e=>{e.ok&&openModalMessage("Finish","Icon saved")})).catch((e=>{console.log(e)}))} )EOF"; diff --git a/src/main.cpp b/src/main.cpp index b06fe4d..ab5377c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,7 @@ * * * AWTRIX 3, a custom firmware for the Ulanzi clock * * * - * Copyright (C) 2023 Stephan Mühl aka Blueforcer * + * Copyright (C) 2024 Stephan Mühl aka Blueforcer * * * * This work is licensed under a * * Creative Commons Attribution-NonCommercial-ShareAlike * @@ -30,6 +30,7 @@ * * ***************************************************************************/ + #include #include "DisplayManager.h" #include "PeripheryManager.h" @@ -94,12 +95,15 @@ void setup() DisplayManager.HSVtext(x, 6, textForDisplay.c_str(), true, 0); x -= 0.18; } - if (MQTT_HOST != "") - { - DisplayManager.HSVtext(4, 6, "MQTT...", true, 0); - MQTTManager.setup(); - MQTTManager.tick(); - } + + + if (MQTT_HOST != "") + { + DisplayManager.HSVtext(4, 6, "MQTT...", true, 0); + MQTTManager.setup(); + MQTTManager.tick(); + } + } else {