From 3535b7543edbcfc28950571f8032f1f33f98f189 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 30 Nov 2021 16:03:57 +0100 Subject: [PATCH] Add support for GPE Multi color smart light Add support for GPE Multi color smart light as sold by Action in the Netherlands --- CHANGELOG.md | 4 + RELEASENOTES.md | 4 +- tasmota/my_user_config.h | 1 + tasmota/support_features.ino | 4 +- tasmota/xlgt_07_lsc_mcsl.ino | 257 +++++++++++++++++++++++++++++++++++ tools/decode-status.py | 7 +- 6 files changed, 272 insertions(+), 5 deletions(-) create mode 100644 tasmota/xlgt_07_lsc_mcsl.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index ef27a353a..fc66c661a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,14 @@ All notable changes to this project will be documented in this file. ## [10.0.0.4] ### Added - (Internal) Support for FUNC_BUTTON_MULTI_PRESSED in (light)drivers +- Support for GPE Multi color smart light as sold by Action in the Netherlands ### Changed - (Internal) Range conversion edge values +### Fixed +- Tuya dimmer range issue (#13849) + ## [10.0.0.3] 20211130 ### Added - Shutter support for venetian blinds with tilt control diff --git a/RELEASENOTES.md b/RELEASENOTES.md index efd16218c..8c8578f3e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -108,6 +108,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Support for HDC2010 temperature/humidity sensor by Luc Boudreau [#13633](https://github.com/arendst/Tasmota/issues/13633) - WS2812 scheme 13 stairs effect [#13595](https://github.com/arendst/Tasmota/issues/13595) - Command ``IfxPeriod `` to overrule ``Teleperiod`` for Influx messages [#13750](https://github.com/arendst/Tasmota/issues/13750) +- Support for GPE Multi color smart light as sold by Action in the Netherlands - Shutter support for venetian blinds with tilt control - ESP32 Proof of Concept Sonoff SPM with limited functionality (switching and energy monitoring) [#13447](https://github.com/arendst/Tasmota/issues/13447) - ESP32 Autoconfiguration @@ -126,7 +127,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - ESP32-C3 core library from v2.0.0-post to ESP32 core library - IRremoteESP8266 library from v2.7.20 to v2.8.0 - (Internal) Range conversion edge values -- ESP8266 Gratuitous ARP enabled and set to 60 seconds (#13623) +- ESP8266 Gratuitous ARP enabled and set to 60 seconds [#13623](https://github.com/arendst/Tasmota/issues/13623) - File editor no-wrap [#13427](https://github.com/arendst/Tasmota/issues/13427) - ESP8266 Gratuitous ARP enabled and set to 60 seconds [#13623](https://github.com/arendst/Tasmota/issues/13623) - Ethernet hostname ending in ``_eth`` to ``-eth`` according to RFC952 @@ -139,6 +140,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Discovery of shutters [#13572](https://github.com/arendst/Tasmota/issues/13572) - ESP32-C3 OneWire as used by DS18x20 [#13583](https://github.com/arendst/Tasmota/issues/13583) - ESP32 analog NTC temperature calculation [#13703](https://github.com/arendst/Tasmota/issues/13703) +- Tuya dimmer range issue [#13849](https://github.com/arendst/Tasmota/issues/13849) ### Removed - ILI9488 driver in favour of Universal Display driver [#13719](https://github.com/arendst/Tasmota/issues/13719) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index d9eb64830..923e19108 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -553,6 +553,7 @@ #define USE_LIGHT_PALETTE // Add support for color palette (+0k7 code) #define USE_LIGHT_VIRTUAL_CT // Add support for Virtual White Color Temperature (+1.1k code) #define USE_DGR_LIGHT_SEQUENCE // Add support for device group light sequencing (requires USE_DEVICE_GROUPS) (+0k2 code) +//#define USE_LSC_MCSL // Add support for GPE Multi color smart light as sold by Action in the Netherlands (+1k1 code) // -- Counter input ------------------------------- #define USE_COUNTER // Enable inputs as counter (+0k8 code) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 9236a511b..59d12e666 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -778,7 +778,9 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_HDC2010) feature8 |= 0x00010000; // xsns_94_hdc2010.ino #endif -// feature8 |= 0x00020000; +#if defined(USE_LIGHT) && defined(USE_LSC_MCSL) + feature8 |= 0x00020000; // xlgt_07_lsc_mcsl.ino +#endif // feature8 |= 0x00040000; // feature8 |= 0x00080000; diff --git a/tasmota/xlgt_07_lsc_mcsl.ino b/tasmota/xlgt_07_lsc_mcsl.ino new file mode 100644 index 000000000..4f71c866f --- /dev/null +++ b/tasmota/xlgt_07_lsc_mcsl.ino @@ -0,0 +1,257 @@ +/* + xlgt_07_lsc_mcsl.ino - GPE Multi color smart light support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_LIGHT +#ifdef USE_LSC_MCSL +/*********************************************************************************************\ + * Golden Power Electronics Integrated Switching Power Supply with Built-in Controller + * GP-SW084-052 uses an ESP8285 (TYWE2S) and submicrocontroller controlling two wire RGB leds + * https://www.gp-electronic.com/product/integrated-switching-power-supply-with-built-in-controller/eugs/european-vertical-6w8-function.html + * + * {"NAME":"LSC MC Lights","GPIO":[1,1,1,1,544,32,1,1,3840,1,3872,1,1,1],"FLAG":0,"BASE":18} + * + * NL: Action LSC Multi color smart lights + * + * Button usage: + * Single press = Power On / Off + * Double press = Cycle Colors + * Triple press = Cycle Effects + * + * HSBColor Color + * ---------- ----------- + * 1 .. 45 R (Red) + * 46 .. 90 RG (Yellow) + * 91 .. 135 G (Green) + * 136 .. 179 GB (Light Blue) + * 180 .. 224 B (Blue) + * 225 .. 269 RB (Purple) + * 270 .. 314 RGB (White) + * 315 .. 360 (Alternating) + * + * Dimmer Effect + * ---------- --------------------------- + * 0 .. 12 Bright (Steady On) + * 13 .. 24 Gradually (Slow Fade) + * 25 .. 37 Star (Sequential) + * 38 .. 49 Flower (In Waves) + * 50 .. 62 Marquee (Chasing / Flash) + * 63 .. 74 Fireworks (Twinkle / Flash) + * 75 .. 87 Meteor + * 88 .. 100 Stream + * + * GPIO04 = Green led + * GPIO05 = Button + * GPIO12 = Data to submicrocontroller + * GPIO14 = Reset to submicrocontroller (26ms active high) +\*********************************************************************************************/ + +#define XLGT_07 7 + +#define LSCMC_GPIO_DATA 12 +#define LSCMC_GPIO_RESET 14 + +#define LSCMC_BIT_TIME 600 // us + +const uint16_t kLscMcData[] PROGMEM = { + //R RG G GB B RB RGB RGBa + 0x0F4D, 0x0745, 0x08B5, 0x0340, 0x0CB0, 0x04B8, 0x0B48, 0x0143, // Bright (Steady on) + 0x8FED, 0x87E5, 0x8815, 0x83E0, 0x8C10, 0x8418, 0x8BE8, 0x81E3, // Gradually (Slow Fade) + 0x70ED, 0x78E5, 0x7715, 0x7CE0, 0x7510, 0x7B18, 0x74E8, 0x7EE3, // Star (Sequential) + 0xCF92, 0xC79A, 0xC86A, 0xC39F, 0xCC6F, 0xC467, 0xCB97, 0xC19C, // Flower (In Waves) + 0x3093, 0x389A, 0x376A, 0x3C9F, 0x336F, 0x3B67, 0x3497, 0x3E9C, // Marquee (Chasing / Flash) + 0xB02D, 0xB825, 0xB7D5, 0xBC20, 0xB3D0, 0xBBD8, 0xB428, 0xBE23, // Fireworks (Twinkle / Flash) + 0x4F2D, 0x4725, 0x48D5, 0x4320, 0x4CD0, 0x44D8, 0x4B28, 0x4123, // Meteor + 0xEFAD, 0xE7A5, 0xE855, 0xE3A1, 0xEC50, 0xE458, 0xEBA8, 0xE1A3 // Stream +}; + +#include +Ticker LscMcStartDelay; + +struct LSCMC { + uint32_t last_send; + uint8_t function; + uint8_t color; + uint8_t dimmer; + uint8_t power; + uint8_t scheme_offset; + uint8_t pin; +} Lscmc; + +/*********************************************************************************************/ + +void LscMcSend(void) { + Lscmc.function &= 0x7; + Lscmc.color &= 0x7; + uint16_t fc = pgm_read_word(kLscMcData + (8 * Lscmc.function) + Lscmc.color); + + uint32_t data; + if (Lscmc.power) { + data = 0xC2FF0000 | fc; + } else { + data = Lscmc.last_send & 0xFF00FFFF; + data ^= 0x0000FF00; + } + + if (data == Lscmc.last_send) { return; } + + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LSC: Function %d, Color %d, State %d, Send %08X"), + Lscmc.function, Lscmc.color, Lscmc.power, data); + + Lscmc.last_send = data; + + digitalWrite(Lscmc.pin, LOW); + delayMicroseconds(LSCMC_BIT_TIME * 15); + digitalWrite(Lscmc.pin, HIGH); + delayMicroseconds(LSCMC_BIT_TIME * 7 + (LSCMC_BIT_TIME / 2)); + digitalWrite(Lscmc.pin, LOW); + delayMicroseconds(LSCMC_BIT_TIME); + digitalWrite(Lscmc.pin, HIGH); + bool last_bit = 0; + bool bit = 0; + uint32_t bit_mask = 0x80000000; + for (uint32_t i = 0; i < 32; i++) { + bit = (data & bit_mask); + if (bit != last_bit) { + delayMicroseconds(LSCMC_BIT_TIME * 3); // Switch bit state + } else { + delayMicroseconds(LSCMC_BIT_TIME); + } + digitalWrite(Lscmc.pin, LOW); + delayMicroseconds(LSCMC_BIT_TIME); + digitalWrite(Lscmc.pin, HIGH); + last_bit = bit; + bit_mask >>= 1; + } +} + +/*********************************************************************************************/ + +bool LscMcSetChannelsFromFunc(void) { + // Use power for Off / On + uint8_t power = Light.power; + bool power_changed = (Lscmc.power != power); + Lscmc.power = power; + + // Use dimmer for function + uint8_t dimmer = light_state.getDimmer(); +/* + dimmer = changeUIntScale(dimmer, 0, 100, 0, 3); + dimmer = changeUIntScale(dimmer, 0, 3, 0, 255); + bool dimmer_changed = (Lscmc.dimmer != dimmer); + Lscmc.dimmer= dimmer; +*/ + uint8_t function = changeUIntScale(dimmer, 0, 100, 0, 7); + bool function_changed = (Lscmc.function != function); + Lscmc.function = function; + + uint16_t hue; + uint8_t sat; + LightGetHSB(&hue, &sat, nullptr); +/* + // Use saturation for function (won't work as if sat = 0 this function is not called) + uint8_t function = changeUIntScale(sat, 0, 255, 0, 7); + bool function_changed = (Lscmc.function != function); + Lscmc.function = function; +*/ + // Use hue for color + uint8_t color = changeUIntScale(hue, 1, 359, 0, 7); + bool color_changed = (Lscmc.color != color); + Lscmc.color = color; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("LSC: Power %d, Hue %d = Color %d, Dimmer %d = Function %d"), +// Lscmc.power, hue, Lscmc.color, dimmer, Lscmc.function); + + if (!power_changed && !function_changed && !color_changed) { return true; } + + static bool first_call = true; + if (first_call) { + LscMcStartDelay.once_ms(900, LscMcSend); // Allow startup time for microcontroller + first_call = false; + } else { + LscMcSend(); + } + + return true; +} + +bool LscMcMultiButtonPressed(void) { + if (XdrvMailbox.index != 0) { return false; } // button_index + + char command[20]; + + uint32_t press_counter = XdrvMailbox.payload; + if (2 == press_counter) { // Color rotate + uint32_t color = Lscmc.color +1; + if (color > 7) { color = 0; } + snprintf_P(command, sizeof(command), PSTR(D_CMND_HSBCOLOR " %d"), (color * (360 / 8)) + ((360 / 8) / 2)); + ExecuteCommand(command, SRC_BUTTON); + } else if (3 == press_counter) { // Function rotate + uint32_t function = Lscmc.function +1; + if (function > 7) { function = 0; } + snprintf_P(command, sizeof(command), PSTR(D_CMND_DIMMER " %d"), (function * (100 / 8)) + ((100 / 8) / 2)); + ExecuteCommand(command, SRC_BUTTON); + } + return true; +} + +void LscMcModuleSelected(void) { + if (!ValidTemplate(PSTR("LSC MC Lights"))) { return; } + if (!PinUsed(GPIO_OUTPUT_HI) || !PinUsed(GPIO_OUTPUT_LO)) { return; } + + Lscmc.pin = Pin(GPIO_OUTPUT_HI); + + uint32_t pin_reset = Pin(GPIO_OUTPUT_LO); + digitalWrite(pin_reset, HIGH); + delay(26); + digitalWrite(pin_reset, LOW); + + Settings->flag.button_single = 0; // SetOption13 - We need multi press detection + Settings->flag3.slider_dimmer_stay_on = 1; // SetOption77 - We need dimmer to keep power on at 0 + + Lscmc.last_send = 0xC2FFEBA8; + + TasmotaGlobal.light_type = LT_RGB; + TasmotaGlobal.light_driver = XLGT_07; +// AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: LSC Multi Color Found")); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xlgt07(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_SET_CHANNELS: + result = LscMcSetChannelsFromFunc(); + break; + case FUNC_BUTTON_MULTI_PRESSED: + result = LscMcMultiButtonPressed(); + break; + case FUNC_MODULE_INIT: + LscMcModuleSelected(); + break; + } + return result; +} + +#endif // USE_LSC_MCSL +#endif // USE_LIGHT \ No newline at end of file diff --git a/tools/decode-status.py b/tools/decode-status.py index f6d8a9b36..1ca16c0ab 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -185,7 +185,8 @@ a_setoption = [[ "(Web) Allow access without referer check", "(Energy) Show phase information", "(Debug) Show heap with logging timestamp", - "","","", + "(Tuya) Allow save dimmer = 0 receved by MCU", + "","", "","","","", "","","","", "","","","" @@ -259,7 +260,7 @@ a_features = [[ "USE_BM8563","USE_ENERGY_DUMMY","USE_AM2320","USE_T67XX", "USE_MCP2515","USE_TASMESH","USE_WIFI_RANGE_EXTENDER","USE_INFLUXDB", "USE_HRG15","USE_VINDRIKTNING","USE_SCD40","USE_HM330X", - "USE_HDC2010","","","", + "USE_HDC2010","USE_LSC_MCSL","","", "","","","", "","","","", "","","","" @@ -290,7 +291,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20211111 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20211130 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))