From 78c7d1a1fe52abc4444fda0766f36b481b33c202 Mon Sep 17 00:00:00 2001 From: tony-fav <42725386+tony-fav@users.noreply.github.com> Date: Sun, 12 Dec 2021 12:23:49 -0500 Subject: [PATCH] DDP schemes for Light and WS2812 --- tasmota/xdrv_04_light.ino | 73 ++++++++++++++++++++++++++++++++++++++ tasmota/xlgt_01_ws2812.ino | 68 ++++++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index b05386f4a..f5504d5f6 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -124,7 +124,11 @@ #define XDRV_04 4 // #define DEBUG_LIGHT +#ifdef USE_NETWORK_LIGHT_SCHEMES +enum LightSchemes { LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_DDP, LS_MAX }; +#else enum LightSchemes { LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX }; +#endif const uint8_t LIGHT_COLOR_SIZE = 25; // Char array scolor size @@ -280,6 +284,11 @@ static uint32_t min3(uint32_t a, uint32_t b, uint32_t c) { return (a < b && a < c) ? a : (b < c) ? b : c; } +#ifdef USE_NETWORK_LIGHT_SCHEMES +WiFiUDP ddp_udp; +uint8_t ddp_udp_up = 0; +#endif + // // LightStateClass // This class is an abstraction of the current light state. @@ -1615,6 +1624,51 @@ void LightCycleColor(int8_t direction) light_controller.calcLevels(Light.new_color); } +#ifdef USE_NETWORK_LIGHT_SCHEMES +void LightListenDDP() +{ + // Light channels gets completely controlled over DDP. So, we don't really check other settings. + // To enter this scheme, we are already assured the light is at least RGB + static uint8_t ddp_color[5] = { 0, 0, 0, 0, 0 }; + + // Can't be trying to initialize UDP too early. + if (TasmotaGlobal.restart_flag || TasmotaGlobal.global_state.network_down) { + light_state.setChannels(ddp_color); + light_controller.calcLevels(Light.new_color); + return; + } + + // Start DDP listener, if fail, just set last ddp_color + if (!ddp_udp_up) { + if (!ddp_udp.begin(4048)) { + light_state.setChannels(ddp_color); + light_controller.calcLevels(Light.new_color); + return; + } + ddp_udp_up = 1; + AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Listener Started: Normal Scheme"); + } + + // Get the DDP payload over UDP + std::vector payload; + while (uint16_t packet_size = ddp_udp.parsePacket()) { + payload.resize(packet_size); + if (!ddp_udp.read(&payload[0], payload.size())) { + continue; + } + } + + // No verification checks performed against packet besides length + if (payload.size() > 12) { + ddp_color[0] = payload[10]; + ddp_color[1] = payload[11]; + ddp_color[2] = payload[12]; + } + light_state.setChannels(ddp_color); + light_controller.calcLevels(Light.new_color); +} +#endif + void LightSetPower(void) { // Light.power = XdrvMailbox.index; @@ -1690,7 +1744,21 @@ void LightAnimate(void) if (Settings->light_scheme >= LS_MAX) { power_off = true; } +#ifdef USE_NETWORK_LIGHT_SCHEMES + if (ddp_udp_up) { + ddp_udp.stop(); + ddp_udp_up = 0; + AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Stopped: Power Off"); + } +#endif } else { +#ifdef USE_NETWORK_LIGHT_SCHEMES + if ((Settings->light_scheme < LS_MAX) && (Settings->light_scheme != LS_DDP) && (ddp_udp_up)) { + ddp_udp.stop(); + ddp_udp_up = 0; + AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Stopped: Normal Scheme not DDP"); + } +#endif switch (Settings->light_scheme) { case LS_POWER: light_controller.calcLevels(Light.new_color); @@ -1743,6 +1811,11 @@ void LightAnimate(void) Light.new_color[2] = changeUIntScale(Light.new_color[2], 0, 255, 0, Settings->light_color[2]); } break; +#ifdef USE_NETWORK_LIGHT_SCHEMES + case LS_DDP: + LightListenDDP(); + break; +#endif default: XlgtCall(FUNC_SET_SCHEME); } diff --git a/tasmota/xlgt_01_ws2812.ino b/tasmota/xlgt_01_ws2812.ino index 3a9e396f3..715851e4c 100644 --- a/tasmota/xlgt_01_ws2812.ino +++ b/tasmota/xlgt_01_ws2812.ino @@ -37,7 +37,11 @@ #define XLGT_01 1 +#ifdef USE_NETWORK_LIGHT_SCHEMES +const uint8_t WS2812_SCHEMES = 10; // Number of WS2812 schemes +#else const uint8_t WS2812_SCHEMES = 9; // Number of WS2812 schemes +#endif const char kWs2812Commands[] PROGMEM = "|" // No prefix D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|" D_CMND_STEPPIXELS ; @@ -167,7 +171,12 @@ WsColor kwanzaa[3] = { 255,0,0, 0,0,0, 0,255,0 }; WsColor kRainbow[7] = { 255,0,0, 255,128,0, 255,255,0, 0,255,0, 0,0,255, 128,0,255, 255,0,255 }; WsColor kFire[3] = { 255,0,0, 255,102,0, 255,192,0 }; WsColor kStairs[2] = { 0,0,0, 255,255,255 }; + +#ifdef USE_NETWORK_LIGHT_SCHEMES +ColorScheme kSchemes[WS2812_SCHEMES -2] = { // Skip clock scheme and DDP scheme +#else ColorScheme kSchemes[WS2812_SCHEMES -1] = { // Skip clock scheme +#endif kIncandescent, 2, kRgb, 3, kChristmas, 2, @@ -492,6 +501,51 @@ void Ws2812Steps(uint32_t schemenr) { Ws2812StripShow(); } +#ifdef USE_NETWORK_LIGHT_SCHEMES +void Ws2812DDP(void) +{ +#if (USE_WS2812_CTYPE > NEO_3LED) + RgbwColor c; + c.W = 0; +#else + RgbColor c; +#endif + c.R = 0; + c.G = 0; + c.B = 0; + + // Can't be trying to initialize UDP too early. + if (TasmotaGlobal.restart_flag || TasmotaGlobal.global_state.network_down) return; + + // Start DDP listener, if fail, just set last ddp_color + if (!ddp_udp_up) { + if (!ddp_udp.begin(4048)) return; + ddp_udp_up = 1; + AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Listener Started: WS2812 Scheme"); + } + + // Get the DDP payload over UDP + std::vector payload; + while (uint16_t packet_size = ddp_udp.parsePacket()) { + payload.resize(packet_size); + if (!ddp_udp.read(&payload[0], payload.size())) { + continue; + } + } + + // No verification checks performed against packet besides length + if (payload.size() > (9+3*Settings->light_pixels)) { + for (uint32_t i = 0; i < Settings->light_pixels; i++) { + c.R = payload[10+3*i]; + c.G = payload[11+3*i]; + c.B = payload[12+3*i]; + strip->SetPixelColor(i, c); + } + Ws2812StripShow(); + } +} +#endif + void Ws2812Clear(void) { strip->ClearTo(0); @@ -580,7 +634,14 @@ bool Ws2812SetChannels(void) void Ws2812ShowScheme(void) { uint32_t scheme = Settings->light_scheme - Ws2812.scheme_offset; - + +#ifdef USE_NETWORK_LIGHT_SCHEMES + if ((scheme != 9) && (ddp_udp_up)) { + ddp_udp.stop(); + ddp_udp_up = 0; + AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Stopped: WS2812 Scheme not DDP"); + } +#endif switch (scheme) { case 0: // Clock if ((1 == TasmotaGlobal.state_250mS) || (Ws2812.show_next)) { @@ -588,6 +649,11 @@ void Ws2812ShowScheme(void) Ws2812.show_next = 0; } break; +#ifdef USE_NETWORK_LIGHT_SCHEMES + case 9: + Ws2812DDP(); + break; +#endif default: if(Settings->light_step_pixels > 0){ Ws2812Steps(scheme -1);