From 33407a45ce69e5be72e18a75352ad36c4544d62d Mon Sep 17 00:00:00 2001 From: gene Date: Tue, 2 Apr 2024 00:45:34 +0200 Subject: [PATCH] v1.2.7 - Added smart LEDs strip/matrix examples - Added *Events.Disable* module property --- examples/color-light/color-light.cpp | 50 ++++++++++++++++++++++---- platformio.ini | 45 +++++++++++++++++++++++ src/io/IOEvent.h | 10 +++--- src/net/NetManager.cpp | 3 +- src/service/EventRouter.cpp | 14 +++++++- src/service/api/devices/ColorLight.cpp | 23 ++++++------ src/service/api/devices/Dimmer.cpp | 13 ++++--- src/service/api/devices/Switch.cpp | 13 ++++--- 8 files changed, 137 insertions(+), 34 deletions(-) diff --git a/examples/color-light/color-light.cpp b/examples/color-light/color-light.cpp index a7da3f8..89967a2 100644 --- a/examples/color-light/color-light.cpp +++ b/examples/color-light/color-light.cpp @@ -36,19 +36,27 @@ using namespace Service::API::devices; HomeGenie* homeGenie; -Adafruit_NeoPixel pixels(1, CONFIG_StatusLedNeoPixelPin, NEO_GRB + NEO_KHZ800); +Adafruit_NeoPixel statusLED(1, CONFIG_StatusLedNeoPixelPin, NEO_GRB + NEO_KHZ800); + +#ifdef LED_ARRAY_COUNT +int num = LED_ARRAY_COUNT; // 90 = 3mt // 30 LEDs per meter (3 mt. strip) +int pin = LED_ARRAY_PIN; +Adafruit_NeoPixel pixels(num, pin, NEO_RGB + NEO_KHZ800); +#endif + +bool changed = false; void statusLedCallback(bool isLedOn) { if (isLedOn) { - pixels.setPixelColor(0, Adafruit_NeoPixel::Color(50, 50, 0)); + statusLED.setPixelColor(0, Adafruit_NeoPixel::Color(50, 50, 0)); } else { - pixels.setPixelColor(0, Adafruit_NeoPixel::Color(0, 0, 0)); + statusLED.setPixelColor(0, Adafruit_NeoPixel::Color(0, 0, 0)); } - pixels.show(); + statusLED.show(); } void setup() { - pixels.begin(); + statusLED.begin(); homeGenie = HomeGenie::getInstance(); @@ -61,11 +69,28 @@ void setup() { auto colorLight = new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, "C1", "Demo Light"); colorLight->onSetColor([](float r, float g, float b) { - pixels.setPixelColor(0, r, g, b); - pixels.show(); + statusLED.setPixelColor(0, g, r, b); +#ifdef LED_ARRAY_COUNT + for (int i = 0; i < num; i++) { + pixels.setPixelColor(i, r, g, b); + } +#endif + changed = true; }); homeGenie->addAPIHandler(colorLight); +#ifdef LED_ARRAY_COUNT + for (int i = 0; i < num; i++) { + auto address = String("L") + String(i + 1); + auto cl = new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, address.c_str(), "Demo Light"); + cl->onSetColor([i](float r, float g, float b) { + pixels.setPixelColor(i, r, g, b); + changed = true; + }); + homeGenie->addAPIHandler(cl); + } +#endif + // TODO: implement color/status recall on start // TODO: implement color/status recall on start // TODO: implement color/status recall on start @@ -75,7 +100,18 @@ void setup() { homeGenie->begin(); } +unsigned long ts = 0; + void loop() { homeGenie->loop(); + + if (changed) { //&& millis()-ts > 50) { // force 20fps max + changed = false; + statusLED.show(); +#ifdef LED_ARRAY_COUNT + pixels.show(); +#endif + ts = millis(); + } } diff --git a/platformio.ini b/platformio.ini index ea02112..28bcc08 100644 --- a/platformio.ini +++ b/platformio.ini @@ -181,6 +181,51 @@ board_build.partitions = min_spiffs.csv lib_deps = ${env.lib_deps} https://github.com/adafruit/Adafruit_NeoPixel@1.12.0 +[env:color-light-c3-25] +platform = espressif32@6.5.0 +board = esp32-c3-devkitc-02 +#board = esp32-c3-devkitm-1 +; change microcontroller +#board_build.mcu = esp32c3 +; change MCU frequency +#board_build.f_cpu = 160000000L +build_flags = -Os -I examples -I src -D ESP32_C3 -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=25 -D LED_ARRAY_PIN=8 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 +build_src_filter = + - + +board_build.flash_size = 4MB +board_build.partitions = min_spiffs.csv +lib_deps = ${env.lib_deps} + https://github.com/adafruit/Adafruit_NeoPixel@1.12.0 + +[env:color-light-c3-64] +platform = espressif32@6.5.0 +board = esp32-c3-devkitc-02 +#board = esp32-c3-devkitm-1 +; change microcontroller +#board_build.mcu = esp32c3 +; change MCU frequency +#board_build.f_cpu = 160000000L +build_flags = -Os -I examples -I src -D ESP32_C3 -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=64 -D LED_ARRAY_PIN=5 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 +build_src_filter = + - + +board_build.flash_size = 4MB +board_build.partitions = min_spiffs.csv +lib_deps = ${env.lib_deps} + https://github.com/adafruit/Adafruit_NeoPixel@1.12.0 + +[env:color-light-c3-90] +platform = espressif32@6.5.0 +board = esp32-c3-devkitc-02 +#board = esp32-c3-devkitm-1 +; change microcontroller +#board_build.mcu = esp32c3 +; change MCU frequency +#board_build.f_cpu = 160000000L +build_flags = -Os -I examples -I src -D ESP32_C3 -D CONFIG_StatusLedPin=-1 -D LED_ARRAY_COUNT=90 -D LED_ARRAY_PIN=5 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 +build_src_filter = + - + +board_build.flash_size = 4MB +board_build.partitions = min_spiffs.csv +lib_deps = ${env.lib_deps} + https://github.com/adafruit/Adafruit_NeoPixel@1.12.0 + [env:shutter] platform = espressif32@6.5.0 diff --git a/src/io/IOEvent.h b/src/io/IOEvent.h index f6ba4cd..90f8c3b 100644 --- a/src/io/IOEvent.h +++ b/src/io/IOEvent.h @@ -61,20 +61,20 @@ namespace IO { virtual void sendEvent(const char *domain, const char *address, const uint8_t *eventPath, void *eventData, IOEventDataType dataType) { if (eventReceiver != nullptr) { eventReceiver->onIOEvent(this, domain, address, eventPath, eventData, dataType); - lastEventMs = millis(); } }; virtual void sendEvent(const uint8_t *eventPath, void *eventData, IOEventDataType dataType) { if (eventReceiver != nullptr && module != nullptr) { - eventReceiver->onIOEvent(this, module->domain.c_str(), module->address.c_str(), eventPath, eventData, dataType); - lastEventMs = millis(); + auto eventsDisable = module->getProperty("Events.Disable"); + if (eventsDisable == nullptr || eventsDisable->value == nullptr || eventsDisable->value != "1") { + eventReceiver->onIOEvent(this, module->domain.c_str(), module->address.c_str(), eventPath, eventData, dataType); + } } }; protected: IIOEventReceiver *eventReceiver = nullptr; - unsigned long lastEventMs = 0; - const Module* module = nullptr; + Module* module = nullptr; }; } diff --git a/src/net/NetManager.cpp b/src/net/NetManager.cpp index 00c6799..eb0b928 100644 --- a/src/net/NetManager.cpp +++ b/src/net/NetManager.cpp @@ -143,7 +143,8 @@ namespace Net { Logger::verbose("%s loop() >> BEGIN", NETMANAGER_LOG_PREFIX); if (ESP_WIFI_STATUS == WL_CONNECTED) { - webSocket->loop(); + for (int i = 0; i < 5; i++) // higher priority + webSocket->loop(); } Logger::verbose("%s loop() << END", NETMANAGER_LOG_PREFIX); diff --git a/src/service/EventRouter.cpp b/src/service/EventRouter.cpp index 931ed78..a37935c 100644 --- a/src/service/EventRouter.cpp +++ b/src/service/EventRouter.cpp @@ -92,7 +92,19 @@ namespace Service { void EventRouter::signalEvent(QueuedMessage m) { if (WiFi.isConnected()) { - eventsQueue.add(m); + bool updated = false; + for (int i = 0; i < eventsQueue.size(); i++) { + auto qm = eventsQueue.get(i); + if (qm.domain == m.domain && qm.sender == m.sender && qm.event == m.event && qm.type == m.type) { + qm.data = m.data; + qm.value = m.value; + updated = true; + break; + } + } + if (!updated) { + eventsQueue.add(m); + } } } diff --git a/src/service/api/devices/ColorLight.cpp b/src/service/api/devices/ColorLight.cpp index f0eaba9..5e83288 100644 --- a/src/service/api/devices/ColorLight.cpp +++ b/src/service/api/devices/ColorLight.cpp @@ -74,17 +74,20 @@ namespace Service { namespace API { namespace devices { color.setColor(o[0], o[1], o[2], o[3]*1000); - // Event Stream Message Enqueue (for MQTT/SSE/WebSocket propagation) - auto eventValue = command->getOption(0); - auto msg = QueuedMessage(m, IOEventPaths::Status_ColorHsb, eventValue, nullptr, IOEventDataType::Undefined); - m->setProperty(IOEventPaths::Status_ColorHsb, eventValue, nullptr, IOEventDataType::Undefined); - HomeGenie::getInstance()->getEventRouter().signalEvent(msg); - // level prop - auto levelValue = String(o[2]); // TODO: use sprintf %.6f - auto msg2 = QueuedMessage(m, IOEventPaths::Status_Level, levelValue, nullptr, IOEventDataType::Undefined); - m->setProperty(IOEventPaths::Status_Level, levelValue, nullptr, IOEventDataType::Undefined); - HomeGenie::getInstance()->getEventRouter().signalEvent(msg2); + auto eventsDisable = module->getProperty("Events.Disable"); + if (eventsDisable == nullptr || eventsDisable->value == nullptr || eventsDisable->value != "1") { + // color + auto eventValue = command->getOption(0); + auto msg = QueuedMessage(m, IOEventPaths::Status_ColorHsb, eventValue, nullptr, IOEventDataType::Undefined); + m->setProperty(IOEventPaths::Status_ColorHsb, eventValue, nullptr, IOEventDataType::Undefined); + HomeGenie::getInstance()->getEventRouter().signalEvent(msg); + // level + auto levelValue = String(o[2]); // TODO: use sprintf %.6f + auto msg2 = QueuedMessage(m, IOEventPaths::Status_Level, levelValue, nullptr, IOEventDataType::Undefined); + m->setProperty(IOEventPaths::Status_Level, levelValue, nullptr, IOEventDataType::Undefined); + HomeGenie::getInstance()->getEventRouter().signalEvent(msg2); + } if (o[2] > 0) { Switch::status = SWITCH_STATUS_ON; diff --git a/src/service/api/devices/Dimmer.cpp b/src/service/api/devices/Dimmer.cpp index 0a217f7..4a93fe1 100644 --- a/src/service/api/devices/Dimmer.cpp +++ b/src/service/api/devices/Dimmer.cpp @@ -57,11 +57,14 @@ namespace Service { namespace API { namespace devices { level.setLevel(l, transition); // Event Stream Message Enqueue (for MQTT/SSE/WebSocket propagation) - auto eventPath = IOEventPaths::Status_Level; - auto eventValue = String(l); - auto msg = QueuedMessage(m, eventPath, eventValue, &l, IOEventDataType::Float); - m->setProperty(eventPath, eventValue, &l, IOEventDataType::Float); - HomeGenie::getInstance()->getEventRouter().signalEvent(msg); + auto eventsDisable = module->getProperty("Events.Disable"); + if (eventsDisable == nullptr || eventsDisable->value == nullptr || eventsDisable->value != "1") { + auto eventPath = IOEventPaths::Status_Level; + auto eventValue = String(l); + auto msg = QueuedMessage(m, eventPath, eventValue, &l, IOEventDataType::Float); + m->setProperty(eventPath, eventValue, &l, IOEventDataType::Float); + HomeGenie::getInstance()->getEventRouter().signalEvent(msg); + } if (l > 0) { Switch::status = SWITCH_STATUS_ON; diff --git a/src/service/api/devices/Switch.cpp b/src/service/api/devices/Switch.cpp index 90f813f..ddf8a20 100644 --- a/src/service/api/devices/Switch.cpp +++ b/src/service/api/devices/Switch.cpp @@ -66,11 +66,14 @@ namespace Service { namespace API { namespace devices { } // Event Stream Message Enqueue (for MQTT/SSE/WebSocket propagation) - float l = status == SWITCH_STATUS_ON ? onLevel : 0; - auto eventValue = String(l); - auto msg = QueuedMessage(m, eventPath, eventValue, &l, IOEventDataType::Float); - m->setProperty(eventPath, eventValue, &l, IOEventDataType::Float); - HomeGenie::getInstance()->getEventRouter().signalEvent(msg); + auto eventsDisable = module->getProperty("Events.Disable"); + if (eventsDisable == nullptr || eventsDisable->value == nullptr || eventsDisable->value != "1") { + float l = status == SWITCH_STATUS_ON ? onLevel : 0; + auto eventValue = String(l); + auto msg = QueuedMessage(m, eventPath, eventValue, &l, IOEventDataType::Float); + m->setProperty(eventPath, eventValue, &l, IOEventDataType::Float); + HomeGenie::getInstance()->getEventRouter().signalEvent(msg); + } responseCallback->writeAll(R"({ "ResponseText": "OK" })");