From 493a124783901dd137c04ac3bd20ebe10cde3d21 Mon Sep 17 00:00:00 2001 From: Paul C Diem Date: Sat, 25 Apr 2020 17:49:34 -0500 Subject: [PATCH] Add DGR light sequence support --- tasmota/i18n.h | 1 + tasmota/my_user_config.h | 3 +- tasmota/support_device_groups.ino | 6 +-- tasmota/tasmota_globals.h | 9 +--- tasmota/xdrv_04_light.ino | 72 +++++++++++++++++++++++++++---- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 534f5de00..9989238fa 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -398,6 +398,7 @@ #define D_CMND_RGBWWTABLE "RGBWWTable" #define D_CMND_ROTATION "Rotation" #define D_CMND_SCHEME "Scheme" +#define D_CMND_SEQUENCE_OFFSET "SequenceOffset" #define D_CMND_SPEED "Speed" #define D_CMND_WAKEUP "Wakeup" #define D_CMND_WAKEUPDURATION "WakeUpDuration" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index e20a653a8..8d4ac7e51 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -426,7 +426,7 @@ #define DEVICE_GROUPS_PORT 4447 // Device groups multicast port #define USE_DEVICE_GROUPS_SEND // Add support for the DevGroupSend command (+0k6 code) #define USE_PWM_DIMMER // Add support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+2k2 code, DGR=0k4) - #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer, also adds device groups support (+0k9 code plus device groups size) + #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer (requires USE_DEVICE_GROUPS) (+0k9 code) //#define USE_KEELOQ // Add support for Jarolift rollers by Keeloq algorithm (+4k5 code) #define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer (+0k7 code) @@ -441,6 +441,7 @@ #define USE_SONOFF_L1 // Add support for Sonoff L1 led control #define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller (+0k3 code) #define USE_LIGHT_PALETTE // Add support for color palette (+0k7 code) +#define USE_DGR_LIGHT_SEQUENCE // Add support for device group light sequencing (requires USE_DEVICE_GROUPS) (+0k2 code) // -- Counter input ------------------------------- #define USE_COUNTER // Enable inputs as counter (+0k8 code) diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino index 1af1c7711..30b5bacc0 100644 --- a/tasmota/support_device_groups.ino +++ b/tasmota/support_device_groups.ino @@ -350,7 +350,7 @@ void SendReceiveDeviceGroupMessage(struct device_group * device_group, struct de else { switch (item) { case DGR_ITEM_LIGHT_CHANNELS: - log_length = snprintf(log_ptr, log_remaining, PSTR("%u,%u,%u,%u,%u"), *message_ptr, *(message_ptr + 1), *(message_ptr + 2), *(message_ptr + 3), *(message_ptr + 4)); + log_length = snprintf(log_ptr, log_remaining, PSTR("%u,%u,%u,%u,%u,%u"), *message_ptr, *(message_ptr + 1), *(message_ptr + 2), *(message_ptr + 3), *(message_ptr + 4), *(message_ptr + 5)); break; } } @@ -549,7 +549,7 @@ bool _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes else { switch (item) { case DGR_ITEM_LIGHT_CHANNELS: - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { *out_ptr++ = strtoul((char *)value_ptr, (char **)&value_ptr, 0); if (*value_ptr == ',') value_ptr++; } @@ -665,7 +665,7 @@ bool _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes else { switch (item) { case DGR_ITEM_LIGHT_CHANNELS: - value = 5; + value = 6; break; } } diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index cae92fe4c..9b72ba954 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -114,15 +114,10 @@ extern "C" void resetPins(); #define MESSZ (MQTT_MAX_PACKET_SIZE -TOPSZ -7) // Max number of characters in JSON message string #endif -#ifdef USE_PWM_DIMMER_REMOTE -#ifdef USE_PWM_DIMMER #ifndef USE_DEVICE_GROUPS -#define USE_DEVICE_GROUPS -#endif // USE_DEVICE_GROUPS -#else // USE_PWM_DIMMER #undef USE_PWM_DIMMER_REMOTE -#endif // USE_PWM_DIMMER -#endif // USE_PWM_DIMMER_REMOTE +#undef USE_DGR_LIGHT_SEQUENCE +#endif // USE_DEVICE_GROUPS #ifndef DOMOTICZ_UPDATE_TIMER #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional) diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 96ffd1f6c..80bfd01d8 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -135,6 +135,9 @@ const char kLightCommands[] PROGMEM = "|" // No prefix #ifdef USE_LIGHT_PALETTE "|" D_CMND_PALETTE #endif // USE_LIGHT_PALETTE +#ifdef USE_DGR_LIGHT_SEQUENCE + "|" D_CMND_SEQUENCE_OFFSET +#endif // USE_DGR_LIGHT_SEQUENCE "|UNDOCA" ; void (* const LightCommand[])(void) PROGMEM = { @@ -144,6 +147,9 @@ void (* const LightCommand[])(void) PROGMEM = { #ifdef USE_LIGHT_PALETTE &CmndPalette, #endif // USE_LIGHT_PALETTE +#ifdef USE_DGR_LIGHT_SEQUENCE + &CmndSequenceOffset, +#endif // USE_DGR_LIGHT_SEQUENCE &CmndUndocA }; // Light color mode, either RGB alone, or white-CT alone, or both only available if ct_rgb_linked is false @@ -284,6 +290,10 @@ struct LIGHT { #ifdef USE_DEVICE_GROUPS uint8_t last_scheme = 0; bool devgrp_no_channels_out = false; // don't share channels with device group (e.g. if scheme set by other device) +#ifdef USE_DGR_LIGHT_SEQUENCE + uint8_t sequence_offset = 0; // number of channel changes this light is behind the master + uint8_t * channels_fifo; +#endif // USE_DGR_LIGHT_SEQUENCE #endif // USE_DEVICE_GROUPS #ifdef USE_LIGHT_PALETTE uint8_t palette_count = 0; // palette entry count @@ -2225,16 +2235,22 @@ void calcGammaBulbs(uint16_t cur_col_10[5]) { void LightSendDeviceGroupStatus(bool force) { static uint8_t last_channels[LST_MAX]; + static uint8_t channels_sequence = 0; static uint8_t last_bri; uint8_t bri = light_state.getBri(); bool send_bri_update = (force || bri != last_bri); if (Light.subtype > LST_SINGLE && !Light.devgrp_no_channels_out) { - uint8_t channels[LST_MAX]; + uint8_t channels[LST_MAX + 1]; light_state.getChannels(channels); - if (force || memcmp(last_channels, channels, LST_MAX)) { + if (force || memcmp(last_channels, channels, LST_MAX) +#ifdef USE_LIGHT_PALETTE + || (Settings.light_scheme && Light.palette_count) +#endif // USE_LIGHT_PALETTE + ) { memcpy(last_channels, channels, LST_MAX); + channels[LST_MAX] = ++channels_sequence; SendLocalDeviceGroupMessage((send_bri_update ? DGR_MSGTYP_PARTIAL_UPDATE : DGR_MSGTYP_UPDATE), DGR_ITEM_LIGHT_CHANNELS, channels); } } @@ -2285,7 +2301,30 @@ void LightHandleDevGroupItem(void) } break; case DGR_ITEM_LIGHT_CHANNELS: - light_controller.changeChannels((uint8_t *)XdrvMailbox.data); +#ifdef USE_DGR_LIGHT_SEQUENCE + { + static uint8_t last_sequence = 0; + + // If a sequence offset is set, set the channels to the ones we received + // changes ago. + if (Light.sequence_offset) { + light_controller.changeChannels(Light.channels_fifo); + + // Shift the fifo down and load the newly received channels at the end for this update and + // any updates we missed. + int last_entry = (Light.sequence_offset - 1) * LST_MAX; + for (uint8_t sequence = (uint8_t)XdrvMailbox.data[LST_MAX]; (uint8_t)(sequence - last_sequence) > 0; last_sequence++) { + memmove(Light.channels_fifo, &Light.channels_fifo[LST_MAX], last_entry); + memcpy(&Light.channels_fifo[last_entry], XdrvMailbox.data, LST_MAX); + } + } + else { +#endif // USE_DGR_LIGHT_SEQUENCE + light_controller.changeChannels((uint8_t *)XdrvMailbox.data); +#ifdef USE_DGR_LIGHT_SEQUENCE + } + } +#endif // USE_DGR_LIGHT_SEQUENCE send_state = true; break; case DGR_ITEM_LIGHT_FIXED_COLOR: @@ -2922,12 +2961,15 @@ void CmndPalette(void) for (int entry = 0; entry < Light.palette_count; entry++) { if (Settings.flag.decimal_text) { // SetOption17 - Switch between decimal or hexadecimal output *p++ = '"'; + for (uint32_t i = 0; i < Light.subtype; i++) { + p += sprintf_P(p, PSTR("%d,"), *palette_entry++); + } + *(p - 1) = '"'; } - memcpy(Light.current_color, palette_entry, Light.subtype); - LightGetColor(p); - p += strlen(p); - if (Settings.flag.decimal_text) { // SetOption17 - Switch between decimal or hexadecimal output - *p++ = '"'; + else { + for (uint32_t i = 0; i < Light.subtype; i++) { + p += sprintf_P(p, PSTR("%02X"), *palette_entry++); + } } *p++ = ','; } @@ -2939,6 +2981,20 @@ void CmndPalette(void) } #endif // USE_LIGHT_PALETTE +#ifdef USE_DGR_LIGHT_SEQUENCE +void CmndSequenceOffset(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) { + if (XdrvMailbox.payload != Light.sequence_offset) { + if (Light.sequence_offset) free(Light.channels_fifo); + Light.sequence_offset = XdrvMailbox.payload; + if (Light.sequence_offset) Light.channels_fifo = (uint8_t *)calloc(Light.sequence_offset, LST_MAX); + } + } + ResponseCmndNumber(Light.sequence_offset); +} +#endif // USE_DGR_LIGHT_SEQUENCE + void CmndUndocA(void) { // Theos legacy status