diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index ee491716..18d5f9af 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: DoozyX/clang-format-lint-action@v0.18.2 with: source: '.' diff --git a/.github/workflows/platformio.yml b/.github/workflows/platformio.yml index e179a94a..6b9e6c76 100644 --- a/.github/workflows/platformio.yml +++ b/.github/workflows/platformio.yml @@ -8,16 +8,16 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} diff --git a/include/Uhr.h b/include/Uhr.h index 5bf5059a..de180f25 100644 --- a/include/Uhr.h +++ b/include/Uhr.h @@ -151,6 +151,8 @@ struct GLOBAL { bool bootShowIP; Birthday birthday[MAX_BIRTHDAY_COUNT]; + + uint8_t ldrType; // 0 = 1 LDR, 1 = 4 LDR parallel }; GLOBAL G = {}; @@ -253,6 +255,7 @@ enum CommandWords { COMMAND_SET_AUTO_BRIGHT = 102, COMMAND_SET_LAYOUT_VARIANT = 103, COMMAND_SET_MQTT_HA_DISCOVERY = 104, + COMMAND_SET_LDR_TYPE = 105, COMMAND_SPEED = 152, @@ -279,6 +282,7 @@ enum ClockType { Ger10x11schwaebisch = 20, Ger10x11Nero = 11, Ger10x11NeroFrame = 26, + Ger10x11bayerisch = 27, Ger11x11 = 3, Ger11x11V2 = 8, Ger11x11V3 = 14, diff --git a/include/Uhrtypes/DE10x11.bayerisch.hpp b/include/Uhrtypes/DE10x11.bayerisch.hpp new file mode 100644 index 00000000..bda8b39d --- /dev/null +++ b/include/Uhrtypes/DE10x11.bayerisch.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include "Uhrtype.hpp" + +/* + * Layout Front + * COL + * X 9 8 7 6 5 4 3 2 1 0 + * ROW + - - - - - - - - - - - + * 0 | E T Z K I S T F Ü N F + * 1 | Z E H N E Z W A N Z G + * 2 | D R E I V I E R T L E + * 3 | J T N O C H V O R X M + * 4 | H O I B E P Z D R E I + * 5 | Z W O A N S S I E M E + * 6 | K A C H T E F Ü N F E + * 7 | N E I N E V I E R E Q + * 8 | Z W O I F E Z E H N E + * 9 | Y S E C H S E F U H R + */ + +class De10x11bayerisch_t : public iUhrType { +public: + virtual LanguageAbbreviation usedLang() override { + return LanguageAbbreviation::DE; + }; + + //------------------------------------------------------------------------------ + + virtual const bool hasDreiviertel() override { return true; } + + //------------------------------------------------------------------------------ + + void show(FrontWord word) override { + switch (word) { + + case FrontWord::es_ist: + setFrontMatrixWord(0, 8, 10); + setFrontMatrixWord(0, 5, 6); + break; + + case FrontWord::nach: + case FrontWord::v_nach: + setFrontMatrixWord(3, 5, 8); + break; + + case FrontWord::vor: + case FrontWord::v_vor: + setFrontMatrixWord(3, 2, 4); + break; + + case FrontWord::viertel: + setFrontMatrixWord(2, 1, 6); + break; + + case FrontWord::dreiviertel: + setFrontMatrixWord(2, 1, 10); + break; + + case FrontWord::min_5: + setFrontMatrixWord(0, 0, 3); + break; + + case FrontWord::min_10: + setFrontMatrixWord(1, 7, 10); + break; + + case FrontWord::min_20: + setFrontMatrixWord(1, 0, 5); + break; + + case FrontWord::halb: + setFrontMatrixWord(4, 6, 10); + break; + + case FrontWord::eins: + setFrontMatrixWord(5, 5, 8); + break; + + case FrontWord::hour_1: + setFrontMatrixWord(5, 5, 8); + break; + + case FrontWord::hour_2: + setFrontMatrixWord(5, 7, 10); + break; + + case FrontWord::hour_3: + setFrontMatrixWord(4, 0, 3); + break; + + case FrontWord::hour_4: + setFrontMatrixWord(7, 1, 5); + break; + + case FrontWord::hour_5: + setFrontMatrixWord(6, 0, 4); + break; + + case FrontWord::hour_6: + setFrontMatrixWord(9, 4, 9); + break; + + case FrontWord::hour_7: + setFrontMatrixWord(5, 0, 4); + break; + + case FrontWord::hour_8: + setFrontMatrixWord(6, 5, 9); + break; + + case FrontWord::hour_9: + setFrontMatrixWord(7, 6, 10); + break; + + case FrontWord::hour_10: + setFrontMatrixWord(8, 0, 4); + break; + + case FrontWord::hour_11: + setFrontMatrixWord(8, 5, 8); + break; + + case FrontWord::hour_12: + setFrontMatrixWord(8, 5, 10); + break; + + default: + break; + }; + }; +}; + +De10x11bayerisch_t _de10x11bayerisch; diff --git a/include/clockWork.h b/include/clockWork.h index 2f278add..3725891c 100644 --- a/include/clockWork.h +++ b/include/clockWork.h @@ -76,6 +76,15 @@ class ClockWork { //------------------------------------------------------------------------------ iUhrType *getPointer(uint8_t type); void initLedStrip(uint8_t num); + float getLuxValue() const { return lux; } + float getAdcValue() const { + uint16_t adcRaw = analogRead(A0); + float voltage = (adcRaw * 3.3f) / 1023.0f; + return round(voltage * 100.0f) / 100.0f; // Runde auf 2 Nachkommastellen + } + uint16_t getAdcRawValue() const { + return analogRead(A0); // Roher ADC-Wert (0-1023) + } //------------------------------------------------------------------------------ // Minute Functions diff --git a/include/clockWork.hpp b/include/clockWork.hpp index 1732a530..d4c59e07 100644 --- a/include/clockWork.hpp +++ b/include/clockWork.hpp @@ -45,13 +45,20 @@ void ClockWork::loopAutoBrightLogic() { if (adcValue < adcValue0Lux) adcValue0Lux = adcValue; float ldrValue = adcValue - adcValue0Lux; - // Derive LUX value from ldrValue via a second degree polinomial. - // The polinomial was derived using an Excel trend line, see - // LDR-Calibration.xlsx - const float x2 = 0.0427; - const float x1 = 2.679; - const float x0 = 10.857; - lux = x2 * ldrValue * ldrValue + x1 * ldrValue + x0; + + // Derive LUX value from ldrValue via a second degree polinomial + // based on LDR type + if (G.ldrType == 0) { // 1 LDR Sensor + const float x2 = 0.0427; + const float x1 = 2.679; + const float x0 = 10.857; + lux = x2 * ldrValue * ldrValue + x1 * ldrValue + x0; + } else { // 4 LDR Sensoren parallel + const float x2 = 0.0005; + const float x1 = 0.0687; + const float x0 = 3.9907; + lux = x2 * ldrValue * ldrValue - x1 * ldrValue + x0; + } } // Based on the LUX value derive the gain for the LEDs 0.0 - 100.0% @@ -104,6 +111,8 @@ iUhrType *ClockWork::getPointer(uint8_t type) { return &_de10x11Nero; case Ger10x11NeroFrame: return &_de10x11NeroFrame; + case Ger10x11bayerisch: + return &_de10x11bayerisch; case Nl10x11: return &_nl10x11; case Ger11x11: @@ -1176,6 +1185,7 @@ void ClockWork::loop(struct tm &tm) { config["bootShowWifi"] = G.bootShowWifi; config["bootShowIP"] = G.bootShowIP; config["autoBrightEnabled"] = G.autoBrightEnabled; + config["ldrType"] = G.ldrType; config["isRomanLanguage"] = isRomanLanguage(); config["hasDreiviertel"] = usedUhrType->hasDreiviertel(); config["hasZwanzig"] = usedUhrType->hasZwanzig(); diff --git a/include/mqtt.h b/include/mqtt.h index 7850a0e1..2c4cbc8e 100644 --- a/include/mqtt.h +++ b/include/mqtt.h @@ -1,9 +1,12 @@ #pragma once -#include +#include "Uhr.h" +#include "clockWork.h" +#include class Mqtt { private: + ClockWork &clockWork; // Referenz auf ClockWork-Instanz void reInit(); static void callback(char *topic, byte *payload, unsigned int length); static void processState(const JsonDocument &doc); @@ -11,15 +14,18 @@ class Mqtt { static void processScrollingText(const JsonDocument &doc); static void processColor(const JsonDocument &doc); static void processBrightness(const JsonDocument &doc); + static bool checkIfMqttUserIsEmpty(); public: - Mqtt() = default; - ~Mqtt() = default; + Mqtt(ClockWork &cw); + ~Mqtt(); void init(); void loop(); void sendState(); void sendDiscovery(); - bool isConnected(); }; + +// Globale Instanz +extern Mqtt *mqttInstance; diff --git a/include/mqtt.hpp b/include/mqtt.hpp index b38ac676..14bca5f8 100644 --- a/include/mqtt.hpp +++ b/include/mqtt.hpp @@ -1,4 +1,3 @@ - #include "Uhr.h" #include "mqtt.h" #include @@ -14,8 +13,20 @@ extern WiFiClient client; +// Global Instance +Mqtt *mqttInstance = nullptr; + PubSubClient mqttClient(client); +// Constructor and Destructor +Mqtt::Mqtt(ClockWork &cw) : clockWork(cw) { mqttInstance = this; } + +Mqtt::~Mqtt() { + if (mqttInstance == this) { + mqttInstance = nullptr; + } +} + // ToDo : MQTT Notify https: // www.home-assistant.io/integrations/notify.mqtt/ //------------------------------------------------------------------------------ @@ -41,12 +52,14 @@ void Mqtt::processState(const JsonDocument &doc) { if (doc.containsKey("state")) { const char *state = doc["state"]; if (!strcmp(state, "ON")) { - Serial.println("ON"); + Serial.println("MQTT: Turning ON"); led.setState(true); } else if (!strcmp(state, "OFF")) { - Serial.println("OFF"); + Serial.println("MQTT: Turning OFF"); led.setState(false); } + if (mqttInstance) + mqttInstance->sendState(); } } @@ -71,27 +84,40 @@ None void Mqtt::processEffect(const JsonDocument &doc) { if (doc.containsKey("effect")) { const char *effect = doc["effect"]; + bool effectChanged = false; + if (!strcmp("Wordclock", effect)) { G.prog = COMMAND_MODE_WORD_CLOCK; - parametersChanged = true; + effectChanged = true; } else if (!strcmp("Seconds", effect)) { G.prog = COMMAND_MODE_SECONDS; + effectChanged = true; } else if (!strcmp("Digitalclock", effect)) { G.prog = COMMAND_MODE_DIGITAL_CLOCK; - parametersChanged = true; + effectChanged = true; } else if (!strcmp("Scrollingtext", effect)) { G.prog = COMMAND_MODE_SCROLLINGTEXT; + effectChanged = true; } else if (!strcmp("Rainbowcycle", effect)) { G.prog = COMMAND_MODE_RAINBOWCYCLE; + effectChanged = true; } else if (!strcmp("Rainbow", effect)) { G.prog = COMMAND_MODE_RAINBOW; + effectChanged = true; } else if (!strcmp("Color", effect)) { G.prog = COMMAND_MODE_COLOR; - parametersChanged = true; + effectChanged = true; } else if (!strcmp("Symbol", effect)) { G.prog = COMMAND_MODE_SYMBOL; + effectChanged = true; + } + + if (effectChanged) { + G.progInit = true; + parametersChanged = true; + if (mqttInstance) + mqttInstance->sendState(); } - G.progInit = true; } } @@ -115,6 +141,14 @@ None void Mqtt::processScrollingText(const JsonDocument &doc) { if (doc.containsKey("scrolling_text")) { strcpy(G.scrollingText, doc["scrolling_text"]); + + // Send update to web interface + StaticJsonDocument<200> webDoc; + webDoc["command"] = "scrolltext"; + webDoc["scrolling_text"] = G.scrollingText; + char buffer[200]; + serializeJson(webDoc, buffer); + webSocket.broadcastTXT(buffer, strlen(buffer)); } } @@ -139,10 +173,31 @@ None void Mqtt::processColor(const JsonDocument &doc) { JsonObjectConst color = doc["color"]; if (!color.isNull()) { - G.color[Foreground] = - HsbColor(float(color["h"]) / 360.f, float(color["s"]) / 100.f, - G.color[Foreground].B); + // Convert values from Home Assistant (0-360 for Hue, 0-100 for + // Saturation) to clock format (0-1 for both) + float h = constrain(color["h"].as(), 0, 360) / 360.0f; + float s = constrain(color["s"].as(), 0, 100) / 100.0f; + + // Keep current brightness + G.color[Foreground] = HsbColor(h, s, G.color[Foreground].B); parametersChanged = true; + + // Save color in EEPROM + eeprom::write(); + + // Send update to web interface + StaticJsonDocument<200> webDoc; + webDoc["command"] = "color"; + webDoc["h"] = round(h * 360); // Convert to 0-360 degrees + webDoc["s"] = round(s * 100); // Convert to 0-100% + webDoc["v"] = round(G.color[Foreground].B * 100); // Convert to 0-100% + char buffer[200]; + serializeJson(webDoc, buffer); + webSocket.broadcastTXT(buffer, strlen(buffer)); + + if (mqttInstance) { + mqttInstance->sendState(); + } } } @@ -168,10 +223,27 @@ None void Mqtt::processBrightness(const JsonDocument &doc) { if (doc.containsKey("brightness")) { + // If Auto-Brightness is enabled, ignore brightness changes from Home + // Assistant + if (G.autoBrightEnabled) { + Serial.println("MQTT: Ignoring brightness change - auto brightness " + "is enabled"); + return; + } + + float brightness = float(uint8_t(doc["brightness"])) / 255.0f; + brightness = max(0.0f, min(1.0f, brightness)); + + // Set brightness directly G.color[Foreground] = - HsbColor(G.color[Foreground].H, G.color[Foreground].S, - uint8_t(doc["brightness"]) / 255.f); + HsbColor(G.color[Foreground].H, G.color[Foreground].S, brightness); + Serial.print("MQTT: Setting manual brightness: "); + Serial.println(brightness); + parametersChanged = true; + + if (mqttInstance) + mqttInstance->sendState(); } } @@ -192,7 +264,7 @@ true if the MQTT user array is empty. false if the MQTT user array is not empty. */ -bool checkIfMqttUserIsEmpty() { +/* static */ bool Mqtt::checkIfMqttUserIsEmpty() { for (uint8_t i = 0; i < PAYLOAD_LENGTH; i++) { if (G.mqtt.user[i] != '\0' && !isSpace(G.mqtt.user[i])) { return false; // Array is not empty @@ -221,16 +293,45 @@ None void Mqtt::init() { mqttClient.setServer(G.mqtt.serverAdress, G.mqtt.port); mqttClient.setCallback(callback); + + // Configure LWT (Last Will and Testament) + String availabilityTopic = String(G.mqtt.topic) + "/availability"; + if (checkIfMqttUserIsEmpty()) { - mqttClient.connect(G.mqtt.clientId); + mqttClient.connect(G.mqtt.clientId, availabilityTopic.c_str(), + 0, // QoS + true, // retain + "offline"); // Last Will Message } else { - mqttClient.connect(G.mqtt.clientId, G.mqtt.user, G.mqtt.password); + mqttClient.connect(G.mqtt.clientId, G.mqtt.user, G.mqtt.password, + availabilityTopic.c_str(), + 0, // QoS + true, // retain + "offline"); // Last Will Message } delay(50); + + // Send online status immediately after connection + mqttClient.publish(availabilityTopic.c_str(), "online", true); + + // Main control mqttClient.subscribe((std::string(G.mqtt.topic) + "/cmd").c_str()); delay(50); + + // Additional Topics + mqttClient.subscribe( + (std::string(G.mqtt.topic) + "/scrolltext/set").c_str()); + delay(50); + mqttClient.subscribe( + (std::string(G.mqtt.topic) + "/effect_speed/set").c_str()); + delay(50); + mqttClient.subscribe( + (std::string(G.mqtt.topic) + "/auto_brightness/set").c_str()); + delay(50); + if (isConnected()) { Serial.println("MQTT Connected"); + sendState(); // Send initial state } } @@ -263,7 +364,6 @@ void Mqtt::reInit() { init(); - // Check if maximum retries reached if (retryCount >= MAX_RETRIES_WITHIN_5_MINUTES) { Serial.println("Switched to hourly MQTT connect retry"); retryIntervall = RETRY_INTERVALL; @@ -314,10 +414,19 @@ None */ void Mqtt::loop() { + static uint32_t lastStateUpdate = 0; + const uint32_t STATE_UPDATE_INTERVAL = 30000; // Alle 30 Sekunden + if (!isConnected()) { reInit(); } mqttClient.loop(); + + // Regular status update + if (millis() - lastStateUpdate >= STATE_UPDATE_INTERVAL) { + sendState(); + lastStateUpdate = millis(); + } } //------------------------------------------------------------------------------ @@ -339,18 +448,47 @@ None */ void Mqtt::callback(char *topic, byte *payload, unsigned int length) { - StaticJsonDocument<512> doc; + // Determine message type based on topic + String topicStr = String(topic); + String baseTopic = String(G.mqtt.topic); // Convert payload to a null-terminated string char msg[length + 1]; memcpy(msg, payload, length); msg[length] = '\0'; - Serial.print("Received message ["); - Serial.print(msg); - Serial.print("] "); + // Process Auto-Brightness messages directly as string + if (topicStr == baseTopic + "/auto_brightness/set") { + if (strcmp(msg, "ON") == 0) { + G.autoBrightEnabled = 1; + Serial.println("MQTT: Auto Brightness ON"); + } else if (strcmp(msg, "OFF") == 0) { + G.autoBrightEnabled = 0; + Serial.println("MQTT: Auto Brightness OFF"); + } else { + Serial.print("MQTT: Unknown command: "); + Serial.println(msg); + } - // Deserialize JSON + parametersChanged = true; + + // Send the new status back + mqttClient.publish( + (std::string(G.mqtt.topic) + "/auto_brightness/state").c_str(), + G.autoBrightEnabled ? "ON" : "OFF", true); + + // Send update to web interface + StaticJsonDocument<200> webDoc; + webDoc["command"] = "autobright"; + webDoc["value"] = G.autoBrightEnabled; + char buffer[200]; + serializeJson(webDoc, buffer); + webSocket.broadcastTXT(buffer, strlen(buffer)); + return; + } + + // For all other messages: JSON deserialization + StaticJsonDocument<512> doc; DeserializationError error = deserializeJson(doc, msg); if (error) { Serial.print(F("deserializeJson() failed: ")); @@ -358,12 +496,44 @@ void Mqtt::callback(char *topic, byte *payload, unsigned int length) { return; } - // Process received JSON data - processState(doc); - processEffect(doc); - processScrollingText(doc); - processColor(doc); - processBrightness(doc); + // Process remaining messages + if (topicStr == baseTopic + "/cmd") { + processState(doc); + processEffect(doc); + processScrollingText(doc); + processColor(doc); + processBrightness(doc); + } else if (topicStr == baseTopic + "/scrolltext/set") { + processScrollingText(doc); + } else if (topicStr == baseTopic + "/effect_speed/set") { + // Process direct string value + int speed = atoi(msg); + if (speed >= 1 && speed <= 10) { + G.effectSpeed = speed; + + // Save changes to EEPROM + eeprom::write(); + parametersChanged = true; + + // If we are in scrolltext mode, reinitialize the program + if (G.prog == COMMAND_MODE_SCROLLINGTEXT) { + G.progInit = true; + } + + // Send new state to Home Assistant + mqttClient.publish( + (std::string(G.mqtt.topic) + "/effect_speed/state").c_str(), + String(G.effectSpeed).c_str(), true); + + // Send update to web interface + StaticJsonDocument<200> webDoc; + webDoc["command"] = "speed"; + webDoc["value"] = G.effectSpeed; + char buffer[200]; + serializeJson(webDoc, buffer); + webSocket.broadcastTXT(buffer, strlen(buffer)); + } + } } //------------------------------------------------------------------------------ @@ -385,20 +555,105 @@ None */ void Mqtt::sendState() { - StaticJsonDocument<200> doc; + // Main status + { + StaticJsonDocument<200> doc; + doc["state"] = (led.getState()) ? "ON" : "OFF"; + + // Calculate actual brightness value + float actualBrightness; + if (G.autoBrightEnabled) { + actualBrightness = (ledGain / 100.0f) * G.color[Foreground].B; + } else { + actualBrightness = G.color[Foreground].B; + } + doc["brightness"] = round(actualBrightness * 255); + doc["color_mode"] = "hs"; + + // Color as object with h and s + JsonObject color = doc.createNestedObject("color"); + color["h"] = round(G.color[Foreground].H * 360); // Hue 0-360 + color["s"] = round(G.color[Foreground].S * 100); // Saturation 0-100 + + switch (G.prog) { + case COMMAND_MODE_WORD_CLOCK: + doc["effect"] = "Wordclock"; + break; + case COMMAND_MODE_SECONDS: + doc["effect"] = "Seconds"; + break; + case COMMAND_MODE_DIGITAL_CLOCK: + doc["effect"] = "Digitalclock"; + break; + case COMMAND_MODE_SCROLLINGTEXT: + doc["effect"] = "Scrollingtext"; + break; + case COMMAND_MODE_RAINBOWCYCLE: + doc["effect"] = "Rainbowcycle"; + break; + case COMMAND_MODE_RAINBOW: + doc["effect"] = "Rainbow"; + break; + case COMMAND_MODE_COLOR: + doc["effect"] = "Color"; + break; + case COMMAND_MODE_SYMBOL: + doc["effect"] = "Symbol"; + break; + } - doc["state"] = (led.getState()) ? "ON" : "OFF"; + char buffer[200]; + serializeJson(doc, buffer); + mqttClient.publish((std::string(G.mqtt.topic) + "/status").c_str(), + buffer, true); + } - JsonObject color = doc.createNestedObject("color"); + // Send diagnostic values + { + StaticJsonDocument<200> doc; + doc["lux"] = round(clockWork.getLuxValue()); // Round lux value + doc["led_gain"] = round(ledGain); // Convert to percent and round + doc["adc_value"] = + clockWork.getAdcValue(); // Voltage value (already rounded) + doc["adc_raw"] = clockWork.getAdcRawValue(); // Raw ADC value + char buffer[200]; + serializeJson(doc, buffer); + mqttClient.publish((std::string(G.mqtt.topic) + "/diagnostics").c_str(), + buffer, true); + } - color["h"] = G.color[Foreground].H * 360; - color["s"] = G.color[Foreground].S * 100; + // Effect speed status - Always update current value + { + mqttClient.publish( + (std::string(G.mqtt.topic) + "/effect_speed/state").c_str(), + String(G.effectSpeed).c_str(), true); + } + + // Scrolling text status + { + StaticJsonDocument<200> doc; + doc["scrolling_text"] = G.scrollingText; + char buffer[200]; + serializeJson(doc, buffer); + mqttClient.publish( + (std::string(G.mqtt.topic) + "/scrolltext/state").c_str(), buffer, + true); + } - doc["brightness"] = G.color[Foreground].B * 255; + // Auto brightness status + { + static bool lastAutoBrightState = G.autoBrightEnabled; + if (lastAutoBrightState != G.autoBrightEnabled) { + mqttClient.publish( + (std::string(G.mqtt.topic) + "/auto_brightness/state").c_str(), + G.autoBrightEnabled ? "ON" : "OFF", true); + lastAutoBrightState = G.autoBrightEnabled; + } + } - char buffer[200]; - serializeJson(doc, buffer); - mqttClient.publish((std::string(G.mqtt.topic) + "/status").c_str(), buffer); + // Update online status + mqttClient.publish((std::string(G.mqtt.topic) + "/availability").c_str(), + "online", true); } //------------------------------------------------------------------------------ @@ -416,87 +671,291 @@ None Output: None - */ - -/* Example MQTT Message -{ - "brightness": true, - "color_mode": true, - "supported_color_modes": [ - "hs" - ], - "schema": "json", - "name": "ESP", - "device": { - "identifiers": [ - "ESPBuro" - ], - "name": "ESP", - "sw_version": "3.3", - "configuration_url": "http://" - }, - "state_topic": "ESPBuro/status", - "command_topic": "ESPBuro/cmd", - "unique_id": "", - "plattform": "mqtt", - "effect": true, - "effect_list": [ - "Wordclock", - "Seconds", - "Digitalclock", - "Scrollingtext", - "Rainbowcycle", - "Rainbow", - "Color", - "Symbol" - ] -} */ void Mqtt::sendDiscovery() { + // Create unique_id based on MAC address + String unique_id = WiFi.macAddress(); + unique_id.replace(":", ""); // Remove colons from MAC address + + // Main light entity + { + StaticJsonDocument<700> root; + mqttClient.setBufferSize(700); + + // Base configuration + root["name"] = String(G.mqtt.clientId); + root["unique_id"] = unique_id; + + // Topics + root["state_topic"] = String(G.mqtt.topic) + "/status"; + root["command_topic"] = String(G.mqtt.topic) + "/cmd"; + root["availability_topic"] = String(G.mqtt.topic) + "/availability"; + root["payload_available"] = "online"; + root["payload_not_available"] = "offline"; + + // Functions + root["brightness"] = true; + root["brightness_scale"] = 255; + JsonArray colorModes = root.createNestedArray("supported_color_modes"); + colorModes.add("hs"); // Correct color mode + root["optimistic"] = false; + + // Schema + root["schema"] = "json"; + + // Effects + root["effect"] = true; + JsonArray effectList = root.createNestedArray("effect_list"); + effectList.add("Wordclock"); + effectList.add("Seconds"); + effectList.add("Digitalclock"); + effectList.add("Scrollingtext"); + effectList.add("Rainbowcycle"); + effectList.add("Rainbow"); + effectList.add("Color"); + effectList.add("Symbol"); + + // Device information + JsonObject device = root.createNestedObject("device"); + JsonArray identifiers = device.createNestedArray("identifiers"); + identifiers.add(unique_id); + device["name"] = G.mqtt.clientId; + device["sw_version"] = VERSION; + device["model"] = "Word Clock"; + device["manufacturer"] = "ESPWortuhr"; + device["configuration_url"] = "http://" + WiFi.localIP().toString(); + + char buffer[700]; + serializeJson(root, buffer); + + String discoveryTopic = String(HOMEASSISTANT_DISCOVERY_TOPIC) + + "/light/" + unique_id + "/config"; + mqttClient.publish(discoveryTopic.c_str(), buffer, true); + } + + // 2. Scrolling Text Switch + { + StaticJsonDocument<512> root; + + root["name"] = "Scrolling Text"; + root["unique_id"] = unique_id + "_scrolltext"; + root["icon"] = "mdi:text"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/scrolltext/state"; + root["command_topic"] = std::string(G.mqtt.topic) + "/scrolltext/set"; + root["value_template"] = "{{ value_json.scrolling_text }}"; + root["command_template"] = "{ \"scrolling_text\": \"{{ value }}\" }"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/text/" + + unique_id + "_scrolltext/config") + .c_str(), + buffer, true); + } + + // 3. Effect Speed + { + StaticJsonDocument<512> root; + + root["name"] = "Effect Speed"; + root["unique_id"] = unique_id + "_effect_speed"; + root["icon"] = "mdi:speedometer"; + root["device_class"] = "speed"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/effect_speed/state"; + root["command_topic"] = std::string(G.mqtt.topic) + "/effect_speed/set"; + root["min"] = 1; + root["max"] = 10; + root["step"] = 1; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/number/" + + unique_id + "_effect_speed/config") + .c_str(), + buffer, true); + } - StaticJsonDocument<700> root; - mqttClient.setBufferSize(700); - - root["brightness"] = true; - root["color_mode"] = true; - - JsonArray colorMode = root.createNestedArray("supported_color_modes"); - colorMode.add("hs"); - - root["schema"] = "json"; - root["name"] = G.mqtt.clientId; - - JsonObject device = root.createNestedObject("device"); - - JsonArray identifiers = device.createNestedArray("identifiers"); - identifiers.add(G.mqtt.topic); - - device["name"] = G.mqtt.clientId; - device["sw_version"] = VERSION; - device["configuration_url"] = "http://" + WiFi.localIP().toString(); - - root["state_topic"] = std::string(G.mqtt.topic) + "/status"; - root["command_topic"] = std::string(G.mqtt.topic) + "/cmd"; - root["unique_id"] = WiFi.macAddress(); - root["plattform"] = "mqtt"; - - root["effect"] = true; - JsonArray effectList = root.createNestedArray("effect_list"); - effectList.add("Wordclock"); - effectList.add("Seconds"); - effectList.add("Digitalclock"); - effectList.add("Scrollingtext"); - effectList.add("Rainbowcycle"); - effectList.add("Rainbow"); - effectList.add("Color"); - effectList.add("Symbol"); - - char buffer[700]; - serializeJson(root, buffer); - mqttClient.publish((std::string(HOMEASSISTANT_DISCOVERY_TOPIC) + - std::string("/light/") + std::string(G.mqtt.topic) + - std::string("/light/config")) - .c_str(), - buffer, true); + // Diagnostic Entities + { + // Lux Sensor + StaticJsonDocument<512> root; + root["name"] = "Illuminance"; + root["unique_id"] = unique_id + "_lux"; + root["device_class"] = "illuminance"; + root["unit_of_measurement"] = "lx"; + root["icon"] = "mdi:white-balance-sunny"; + root["state_class"] = "measurement"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/diagnostics"; + root["value_template"] = "{{ value_json.lux }}"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/sensor/" + + unique_id + "_lux/config") + .c_str(), + buffer, true); + } + + { + // LED Gain Sensor + StaticJsonDocument<512> root; + root["name"] = "LED Gain"; + root["unique_id"] = unique_id + "_led_gain"; + root["device_class"] = "power_factor"; + root["unit_of_measurement"] = "%"; + root["icon"] = "mdi:brightness-percent"; + root["state_class"] = "measurement"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/diagnostics"; + root["value_template"] = "{{ value_json.led_gain }}"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/sensor/" + + unique_id + "_led_gain/config") + .c_str(), + buffer, true); + } + + { + // ADC Value Sensor + StaticJsonDocument<512> root; + root["name"] = "ADC Value"; + root["unique_id"] = unique_id + "_adc_value"; + root["device_class"] = "voltage"; + root["unit_of_measurement"] = "V"; + root["icon"] = "mdi:flash"; + root["state_class"] = "measurement"; + root["value_template"] = "{{ value_json.adc_value | round(2) }}"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/diagnostics"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/sensor/" + + unique_id + "_adc_value/config") + .c_str(), + buffer, true); + } + + { + // ADC Raw Value Sensor + StaticJsonDocument<512> root; + root["name"] = "ADC Raw Value"; + root["unique_id"] = unique_id + "_adc_raw"; + root["unit_of_measurement"] = ""; + root["icon"] = "mdi:flash"; + root["state_class"] = "measurement"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = std::string(G.mqtt.topic) + "/diagnostics"; + root["value_template"] = "{{ value_json.adc_raw | int }}"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/sensor/" + + unique_id + "_adc_raw/config") + .c_str(), + buffer, true); + } + + // Send online status + mqttClient.publish((std::string(G.mqtt.topic) + "/availability").c_str(), + "online", true); + + // Auto brightness switch + { + StaticJsonDocument<512> root; + root["name"] = "Auto Brightness"; + root["unique_id"] = unique_id + "_auto_brightness"; + root["icon"] = "mdi:brightness-auto"; + root["device_class"] = "switch"; + + JsonObject deviceCopy = root.createNestedObject("device"); + JsonArray deviceIdentifiers = + deviceCopy.createNestedArray("identifiers"); + deviceIdentifiers.add(unique_id); + deviceCopy["name"] = G.mqtt.clientId; + deviceCopy["sw_version"] = VERSION; + deviceCopy["model"] = "Word Clock"; + deviceCopy["manufacturer"] = "ESPWortuhr"; + deviceCopy["configuration_url"] = "http://" + WiFi.localIP().toString(); + + root["state_topic"] = + std::string(G.mqtt.topic) + "/auto_brightness/state"; + root["command_topic"] = + std::string(G.mqtt.topic) + "/auto_brightness/set"; + root["payload_on"] = "ON"; + root["payload_off"] = "OFF"; + + char buffer[512]; + serializeJson(root, buffer); + mqttClient.publish((String(HOMEASSISTANT_DISCOVERY_TOPIC) + "/switch/" + + unique_id + "_auto_brightness/config") + .c_str(), + buffer, true); + } } diff --git a/include/webPageAdapter.h b/include/webPageAdapter.h index 6b46e55b..5f7a387f 100644 --- a/include/webPageAdapter.h +++ b/include/webPageAdapter.h @@ -369,6 +369,14 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, //------------------------------------------------------------------------------ + case COMMAND_SET_LDR_TYPE: { + G.ldrType = split(payload, 3); + eeprom::write(); + break; + } + + //------------------------------------------------------------------------------ + case COMMAND_SET_LANGUAGE_VARIANT: { G.languageVariant[ItIs15] = split(payload, 3); G.languageVariant[ItIs20] = split(payload, 6); diff --git a/src/Wortuhr.cpp b/src/Wortuhr.cpp index d82ebcc7..521d3d1b 100644 --- a/src/Wortuhr.cpp +++ b/src/Wortuhr.cpp @@ -69,7 +69,7 @@ Transition *transition; SecondsFrame *secondsFrame; Led led; ClockWork clockWork; -Mqtt mqtt; +Mqtt mqtt(clockWork); Network network; #include "Transitiontypes/Transition.hpp" @@ -220,6 +220,7 @@ void setup() { G.layoutVariant[ReverseMinDirection] = REVERSE_MINUTE_DIR; G.layoutVariant[MirrorVertical] = MIRROR_FRONT_VERTICAL; G.layoutVariant[MirrorHorizontal] = MIRROR_FRONT_HORIZONTAL; + G.ldrType = 0; // Standard: Einzelner LDR for (uint8_t i = 0; i < sizeof(G.languageVariant) / sizeof(G.languageVariant[0]); i++) { diff --git a/webpage/index.html b/webpage/index.html index 05dd3187..db916324 100644 --- a/webpage/index.html +++ b/webpage/index.html @@ -345,6 +345,7 @@

+ @@ -700,6 +701,14 @@


+
+ + +
+
diff --git a/webpage/language/de.js b/webpage/language/de.js index 250a4d30..d6775d3e 100644 --- a/webpage/language/de.js +++ b/webpage/language/de.js @@ -128,6 +128,7 @@ let TRANSLATION_DE_DE = { "de-10-11-clock": "🇩🇪 10 × 11 Uhr", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Rahmen", + "de-10-11-bayerisch": "🇩🇪 10 × 11 Bayerisch", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Schwäbisch", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 Version 2", @@ -270,7 +271,10 @@ let TRANSLATION_DE_DE = { "value-offset": "Offset (0–255)", "help-slope": "Konfiguration der Steilheit:
Sie bestimmt den Grad der LED-Helligkeitsänderung bei Änderung des Umgebungslichts.
" + "0=schwache LED-Helligkeitsänderung, 16=neutrale LED-Helligkeitsänderung, 255=starke LED-Helligkeitsänderung", - "value-slope": "Steilheit (0–255)" + "value-slope": "Steilheit (0–255)", + "ldr-type": "LDR-Konfiguration:", + "ldr-single": "Einzelner LDR", + "ldr-quad": "Vier LDR parallel" }, "hostname": { "h2": "Hostname", diff --git a/webpage/language/en.js b/webpage/language/en.js index 8330c76f..2ad79cb5 100644 --- a/webpage/language/en.js +++ b/webpage/language/en.js @@ -128,6 +128,7 @@ let TRANSLATION_EN_US = { "de-10-11-clock": "🇩🇪 10 × 11 Clock", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Frame", + "de-10-11-bayerisch": "🇩🇪 10 × 11 Bavarian", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Swabian Style", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 Version 2", @@ -270,7 +271,10 @@ let TRANSLATION_EN_US = { "value-offset": "Offset (0–255)", "help-slope": "Configuration of the slope:
It determines the degree of LED brightness change when the ambient light changes.
" + "0=weak LED brightness change, 16=neutral LED brightness change, 255=strong LED brightness change", - "value-slope": "Slope (0–255)" + "value-slope": "Slope (0–255)", + "ldr-type": "LDR Configuration:", + "ldr-single": "Single LDR", + "ldr-quad": "Four LDR parallel" }, "hostname": { "h2": "Hostname", diff --git a/webpage/language/es.js b/webpage/language/es.js index 5214fd60..1e47db7b 100644 --- a/webpage/language/es.js +++ b/webpage/language/es.js @@ -104,6 +104,7 @@ let TRANSLATION_ES = { "de-10-11-clock": "🇩🇪 10 × 11 Uhr", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Rahmen", + "de-10-11-bayerisch": "🇩🇪 10 × 11 bávaro", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Estilo suabo", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 Version 2", @@ -241,9 +242,12 @@ let TRANSLATION_ES = { "help-offset": "Configuration of the brightness offset:
It determines the minimum brightness of the LEDs at 0 lux ambient light:
" + "0=LEDs off, n=LED brightness is n/255, 255=LEDs always have the maximum brightness", "value-offset": "Offset (0–255)", - "help-slope": "Configuration of the slope:
It determines the degree of LED brightness change when the ambient light changes.
" + - "0=weak LED brightness change, 16=neutral LED brightness change, 255=strong LED brightness change", - "value-slope": "Slope (0–255)" + "help-slope": "Configuración de la pendiente:
Determina el grado de cambio de brillo del LED cuando cambia la luz ambiental.
" + + "0=cambio de brillo LED débil, 16=cambio de brillo LED neutral, 255=cambio de brillo LED fuerte", + "value-slope": "Pendiente (0–255)", + "ldr-type": "Configuración LDR:", + "ldr-single": "LDR individual", + "ldr-quad": "Cuatro LDR en paralelo" }, "hostname": { "h2": "Hostname", diff --git a/webpage/language/hu.js b/webpage/language/hu.js index c05d0792..333bcaaa 100644 --- a/webpage/language/hu.js +++ b/webpage/language/hu.js @@ -104,6 +104,7 @@ let TRANSLATION_HU = { "de-10-11-clock": "🇩🇪 10 × 11 óra", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero keretek", + "de-10-11-bayerisch": "🇩🇪 10 × 11 bajor", "de-10-11-schwaebisch": "🇩🇪 10 × 11 sváb stílus", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 verzió 2", @@ -241,9 +242,12 @@ let TRANSLATION_HU = { "help-offset": "A fényerő eltolás konfigurálása:
Meghatározza a LED-ek minimális fényerejét 0 lux környezeti fénynél:
" + "0=LED-ek kikapcsolva, n=LED fényerőssége n/255, 255=LED-ek mindig maximális fényerősségűek.", "value-offset": "Offset (0–255)", - "help-slope": "A lejtő konfigurációja:
Meghatározza a LED fényerejének változásának mértékét, amikor a környezeti fény változik.
" + - "0=gyenge LED-fényerő változás, 16=semleges LED-fényerő változás, 255=erős LED-fényerő változás.", - "value-slope": "Lejtő (0–255)" + "help-slope": "A meredekség konfigurálása:
Meghatározza a LED fényerő változásának mértékét a környezeti fény változásakor.
" + + "0=gyenge LED fényerő változás, 16=semleges LED fényerő változás, 255=erős LED fényerő változás", + "value-slope": "Meredekség (0–255)", + "ldr-type": "LDR konfiguráció:", + "ldr-single": "Egyetlen LDR", + "ldr-quad": "Négy LDR párhuzamosan" }, "hostname": { "h2": "Host-név", diff --git a/webpage/language/it.js b/webpage/language/it.js index 06c4772c..29785f6b 100644 --- a/webpage/language/it.js +++ b/webpage/language/it.js @@ -104,6 +104,7 @@ let TRANSLATION_IT = { "de-10-11-clock": "🇩🇪 10 × 11 Uhr", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Rahmen", + "de-10-11-bayerisch": "🇩🇪 10 × 11 bavarese", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Stile svevo", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 Version 2", @@ -241,9 +242,12 @@ let TRANSLATION_IT = { "help-offset": "Configurazione dell'offset di luminosità:
Determina la luminosità minima dei LED a 0 lux di luce ambientale:
" + "0=LED spenti, n=luminosità dei LED pari a n/255, 255=LED sempre con la massima luminosità", "value-offset": "Offset (0–255)", - "help-slope": "Configurazione della pendenza:
Determina il grado di variazione della luminosità del LED al variare della luce ambientale.
" + - "0=modifica debole della luminosità del LED, 16=modifica neutra della luminosità del LED, 255=modifica forte della luminosità del LED.", - "value-slope": "Pendenza (0–255)" + "help-slope": "Configurazione della pendenza:
Determina il grado di variazione della luminosità del LED quando cambia la luce ambientale.
" + + "0=variazione debole della luminosità LED, 16=variazione neutra della luminosità LED, 255=variazione forte della luminosità LED", + "value-slope": "Pendenza (0–255)", + "ldr-type": "Configurazione LDR:", + "ldr-single": "LDR singolo", + "ldr-quad": "Quattro LDR in parallelo" }, "hostname": { "h2": "Hostname", diff --git a/webpage/language/nl.js b/webpage/language/nl.js index d5292306..44efae9b 100644 --- a/webpage/language/nl.js +++ b/webpage/language/nl.js @@ -104,6 +104,7 @@ let TRANSLATION_NL = { "de-10-11-clock": "🇩🇪 10 × 11 Clock", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Frame", + "de-10-11-bayerisch": "🇩🇪 10 × 11 Beiers", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Zwabische stijl", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 Versie 2", @@ -244,9 +245,12 @@ let TRANSLATION_NL = { "help-offset": "Configuratie van de helderheidsoffset:
Deze bepaalt de minimale helderheid van de LED's bij 0 lux omgevingslicht:
" + "0=LEDs uit, n=LED-helderheid is n/255, 255=LEDs hebben altijd de maximale helderheid", "value-offset": "Offset (0–255)", - "help-slope": "Configuratie van de helling:
deze bepaalt de mate waarin de LED-helderheid verandert wanneer het omgevingslicht verandert.
" + - "0=zwakke LED helderheidsverandering, 16=neutrale LED helderheidsverandering, 255=sterke LED helderheidsverandering", - "value-slope": "Donker (0 – 255)" + "help-slope": "Configuratie van de helling:
Bepaalt de mate van LED-helderheidsverandering bij verandering van omgevingslicht.
" + + "0=zwakke LED-helderheidsverandering, 16=neutrale LED-helderheidsverandering, 255=sterke LED-helderheidsverandering", + "value-slope": "Helling (0–255)", + "ldr-type": "LDR-configuratie:", + "ldr-single": "Enkele LDR", + "ldr-quad": "Vier LDR parallel" }, "hostname": { "h2": "Hostnaam", diff --git a/webpage/language/ru.js b/webpage/language/ru.js index 2b05c23c..c12aa721 100755 --- a/webpage/language/ru.js +++ b/webpage/language/ru.js @@ -92,6 +92,7 @@ let TRANSLATION_RU = { "de-10-11-clock": "🇩🇪 10 × 11 Часы", "de-10-11-nero": "🇩🇪 10 × 11 Nero", "de-10-11-nero-frame": "🇩🇪 10 × 11 Nero Rahmen", + "de-10-11-bayerisch": "🇩🇪 10 × 11 Баварский", "de-10-11-schwaebisch": "🇩🇪 10 × 11 Швабия", "de-11-11": "🇩🇪 11 × 11", "de-11-11-v2": "🇩🇪 11 × 11 V2", @@ -229,9 +230,12 @@ let TRANSLATION_RU = { "help-offset": "Конфигурация смещения яркости:
Определяет минимальную яркость светодиодов при освещенности 0 люкс:
" + "0=Светодиоды выключены, n=Яркость светодиодов равна n/255, 255=Светодиоды всегда имеют максимальную яркость", "value-offset": "Смещение (0–255)", - "help-slope": "Конфигурация наклона:
Определяет степень изменения яркости светодиода при изменении освещенности.
" + - "0=слабое изменение яркости светодиода, 16=нейтральное изменение яркости светодиода, 255=сильное изменение яркости светодиода", - "value-slope": "Склон (0–255)" + "help-slope": "Настройка наклона:
Определяет степень изменения яркости светодиодов при изменении окружающего освещения.
" + + "0=слабое изменение яркости, 16=нейтральное изменение яркости, 255=сильное изменение яркости", + "value-slope": "Наклон (0–255)", + "ldr-type": "Конфигурация LDR:", + "ldr-single": "Один LDR", + "ldr-quad": "Четыре LDR параллельно" }, "hostname": { "h2": "Имя хоста", diff --git a/webpage/script.js b/webpage/script.js index 89ed60d6..9c6cbc38 100644 --- a/webpage/script.js +++ b/webpage/script.js @@ -150,6 +150,7 @@ var COMMAND_SET_BOOT = 101; var COMMAND_SET_AUTO_BRIGHT = 102; var COMMAND_SET_LAYOUT_VARIANT = 103; var COMMAND_SET_MQTT_HA_DISCOVERY = 104; +var COMMAND_SET_LDR_TYPE = 105; var COMMAND_SPEED = 152; @@ -343,6 +344,16 @@ function initWebsocket() { $("#mqtt-topic").set("value", data.MQTT_Topic); } + if (data.command === "scrolltext") { + $("#scrollingtext").set("value", data.scrolling_text); + } + + if (data.command === "speed") { + $("#slider-speed").set("value", data.value); + $("#slider-speed-value").fill(data.value); + effectSpeed = data.value; + } + if (data.command === "birthdays") { hasHappyBirthday = data.hasHappyBirthday; $("#birthdays-date0").set("value", data.birthdayDate0); @@ -420,6 +431,7 @@ function initWebsocket() { $("#auto-bright-enabled").set("value", autoBrightEnabled); enableSpecific("specific-layout-brightness-man", autoBrightEnabled === 0); enableSpecific("specific-layout-brightness-auto", autoBrightEnabled === 1); + $("#ldr-type").set("value", data.ldrType); } if (data.command === "set") { hsb[0][0] = data.hsb00; @@ -569,15 +581,9 @@ function updateManualTimeInput() { } function autoBrightUpdater() { - if (autoBrightInterval !== null || autoBrightEnabled !== 1) { - return; + if (autoBrightEnabled === 1) { + sendCmd(COMMAND_REQUEST_AUTO_BRIGHT); } - autoBrightInterval = setInterval(function() { - if ($("#auto-bright-enabled").get("value") === "1") { - sendCmd(COMMAND_REQUEST_AUTO_BRIGHT, 1); - } - }, 1000); // 1000 milliseconds intervall - debugMessage(`Start timer autoBrightInterval with ID ${autoBrightInterval}`); } function autoBrightStop() { @@ -993,4 +999,13 @@ $.ready(function() { sendCmd(COMMAND_SET_WHITETYPE, nstr(wType)); debugMessage("whitetype" + debugMessageReconfigured); }); + $("#ldr-type").on("change", function() { + setLdrType(); + }); }); + +function setLdrType() { + var ldrType = $("#ldr-type").get("value"); + sendCmd(COMMAND_SET_LDR_TYPE, ldrType); + debugMessage("LDR type" + debugMessageReconfigured); +}