diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index ede627571..b2badf70f 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,7 @@ * 6.6.0.20 20191018 * Add command SetOption65 0/1 to disable (1) fast power cycle detection fixing unwanted brownout trigger * Add absolute PowerDelta using command PowerDelta 101..32000 where 101 = 101-100 = 1W, 202 = 202-100 = 102W (#5901) + * Add support for EX-Store WiFi Dimmer V4 (#5856) * * 6.6.0.19 20191018 * Replace obsolete xsns_23_sdm120 with xnrg_08_sdm120 and consolidate define USE_SDM120 diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 29e932cfc..a24e95d70 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 948853f3d..31b23dac9 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 2627e3986..849d356af 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 7dc1bdad1..325558b83 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 1ce9f12b9..5cee90b5c 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-ES.h b/sonoff/language/es-ES.h index f9ce932a3..f5f31ffc6 100644 --- a/sonoff/language/es-ES.h +++ b/sonoff/language/es-ES.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index a0cee0290..b52156447 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index c609b5ac6..52c9d8cf9 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index b014b531a..635756447 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 46ab48e52..7a35a4dfc 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ko-KO.h b/sonoff/language/ko-KO.h index 6da901543..6ae84f9a7 100644 --- a/sonoff/language/ko-KO.h +++ b/sonoff/language/ko-KO.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 728b5249e..fd94dbe09 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index a1610bef0..b871a18ea 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 737e785a4..b4048fe8c 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index f6f106bce..80ac976b7 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index c03ae5feb..543d8a4f1 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index 6ca306f54..207764960 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index f03aa1539..79cf9dedc 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 39881132e..f28f951d9 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 02ac21a24..0ea4127c7 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 264964b2e..22ac1f9cf 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 3c3afd739..437656457 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -626,6 +626,7 @@ #define D_SENSOR_SM2135_CLK "SM2135 Clk" #define D_SENSOR_SM2135_DAT "SM2135 Dat" #define D_SENSOR_DEEPSLEEP "DeepSleep" +#define D_SENSOR_EXS_MCU_RESET "EXS Reset" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index ad25e3b3a..33a3f9208 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -321,6 +321,8 @@ #define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0)) //#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code) //#define USE_DEEPSLEEP // Add support for deepsleep (+1k code) +//#define USE_EXS_DIMMER // Add support for ES-Store WiFi Dimmer (+1k5 code) +// #define EXS_MCU_CMNDS // Add command to send MCU commands (+0k8 code) // -- Optional light modules ---------------------- #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 1446d8946..8e0e95cf4 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -101,6 +101,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0)) //#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code) //#define USE_DEEPSLEEP // Add support for deepsleep (+1k code) +//#define USE_EXS_DIMMER // Add support for EX-Store WiFi Dimmer // -- Optional light modules ---------------------- #define USE_LIGHT // Add Dimmer/Light support @@ -256,6 +257,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller #undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) #undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer // -- Optional light modules ---------------------- //#undef USE_LIGHT // Disable Dimmer/Light support @@ -364,6 +366,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller #undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) #undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer #undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) #undef USE_PZEM004T // Disable PZEM004T energy sensor @@ -435,6 +438,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller #undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) #undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer // -- Optional light modules ---------------------- //#undef USE_LIGHT // Also disable all Dimmer/Light support @@ -532,6 +536,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller #undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) #undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer // -- Optional light modules ---------------------- //#undef USE_LIGHT // Also disable all Dimmer/Light support @@ -631,6 +636,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_ARILUX_RF // Disable support for Arilux RF remote controller #undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) #undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer // -- Optional light modules ---------------------- #undef USE_LIGHT // Disable support for lights diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 2a3ddcaca..c6ed63361 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -207,6 +207,7 @@ enum UserSelectablePins { GPIO_SM2135_CLK, // SM2135 Clk GPIO_SM2135_DAT, // SM2135 Dat GPIO_DEEPSLEEP, // Kill switch for deepsleep + GPIO_EXS_MCU_RESET, // EXS MCU Reset GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -284,7 +285,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_DDS2382_TX "|" D_SENSOR_DDS2382_RX "|" D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|" D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|" - D_SENSOR_DEEPSLEEP "|" + D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_MCU_RESET "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -392,6 +393,7 @@ enum SupportedModules { SYF05, SONOFF_L1, SONOFF_IFAN03, + EXS_DIMMER, MAXMODULE}; #define USER_MODULE 255 @@ -573,6 +575,9 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_TUYA_TX, // Tuya Serial interface GPIO_TUYA_RX, // Tuya Serial interface #endif +#ifdef USE_EXS_DIMMER + GPIO_EXS_MCU_RESET, // EXS MCU Reset +#endif #endif // USE_LIGHT #if defined(USE_IR_REMOTE) || defined(USE_IR_REMOTE_FULL) @@ -803,6 +808,9 @@ const uint8_t kModuleNiceList[] PROGMEM = { #endif #ifdef USE_PS_16_DZ PS_16_DZ, +#endif +#ifdef USE_EXS_DIMMER + EXS_DIMMER, #endif H801, // Light Devices MAGICHOME, @@ -2122,6 +2130,27 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_REL2, // GPIO14 WIFI_O1 Relay 2 (0 = Off, 1 = On) controlling the fan GPIO_REL4, // GPIO15 WIFI_O3 Relay 4 (0 = Off, 1 = On) controlling the fan 0, 0 + }, + { "EXS Dimmer", // EXS_DIMMER - EX-Stroe WiFi Dimmer v4, two channel (ESP8266 w/ separate MCU dimmer) + // https://ex-store.de/2-Kanal-RS232-WiFi-WLan-Dimmer-Modul-V4-fuer-Unterputzmontage-230V-3A + // https://ex-store.de/2-Kanal-RS232-WiFi-WLan-Dimmer-Modul-V4-fuer-Unterputzmontage-230V-3A-ESP8266-V12-Stift-und-Buchsenleisten + 0, + GPIO_TXD, // GPIO01 MCU serial control + 0, + GPIO_RXD, // GPIO03 MCU serial control + GPIO_USER, // GPIO04 + GPIO_USER, // GPIO05 + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_USER, // GPIO12 + GPIO_EXS_MCU_RESET, // GPIO13 EXS MCU Reset + GPIO_USER, // GPIO14 + 0, // GPIO15 + 0, 0 } }; diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 6ee9afe21..a159377d8 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -472,9 +472,11 @@ void GetFeatures(void) feature5 |= 0x00002000; // xdrv_06_snfbridge.ino #endif #ifdef USE_SONOFF_L1 - feature5 |= 0x00004000; + feature5 |= 0x00004000; // xlgt_05_sonoff_l1.ino +#endif +#ifdef USE_EXS_DIMMER + feature5 |= 0x00008000; // xdrv_30_exs_dimmer.ino #endif -// feature5 |= 0x00008000; // feature5 |= 0x00010000; // feature5 |= 0x00020000; diff --git a/sonoff/xdrv_30_exs_dimmer.ino b/sonoff/xdrv_30_exs_dimmer.ino new file mode 100644 index 000000000..63b489b56 --- /dev/null +++ b/sonoff/xdrv_30_exs_dimmer.ino @@ -0,0 +1,624 @@ +/* + xdrv_30_exs_dimmer.ino - ex-store dimmer support for Sonoff-Tasmota + + Copyright (C) 2019 Andreas Schultz + + 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_EXS_DIMMER +/*********************************************************************************************\ + * EX-Store WiFi Dimmer V4 + * https://ex-store.de/2-Kanal-RS232-WiFi-WLan-Dimmer-Modul-V4-fuer-Unterputzmontage-230V-3A + * https://ex-store.de/2-Kanal-RS232-WiFi-WLan-Dimmer-Modul-V4-fuer-Unterputzmontage-230V-3A-ESP8266-V12-Stift-und-Buchsenleisten +\*********************************************************************************************/ +//#define EXS_DEBUG + +#define XDRV_30 30 + +#define EXS_GATE_1_ON 0x20 +#define EXS_GATE_1_OFF 0x21 +#define EXS_DIMM_1_ON 0x22 +#define EXS_DIMM_1_OFF 0x23 +#define EXS_DIMM_1_TBL 0x24 +#define EXS_DIMM_1_VAL 0x25 +#define EXS_GATE_2_ON 0x30 +#define EXS_GATE_2_OFF 0x31 +#define EXS_DIMM_2_ON 0x32 +#define EXS_DIMM_2_OFF 0x33 +#define EXS_DIMM_2_TBL 0x34 +#define EXS_DIMM_2_VAL 0x35 +#define EXS_GATES_ON 0x40 +#define EXS_GATES_OFF 0x41 +#define EXS_DIMMS_ON 0x50 +#define EXS_DIMMS_OFF 0x51 +#define EXS_CH_LOCK 0x60 +#define EXS_GET_VALUES 0xFA +#define EXS_WRITE_EE 0xFC +#define EXS_READ_EE 0xFD +#define EXS_GET_VERSION 0xFE +#define EXS_RESET 0xFF + +#define EXS_BUFFER_SIZE 256 +#define EXS_ACK_TIMEOUT 200 // 200 ms ACK timeout + +#include + +TasmotaSerial *ExsSerial = nullptr; + +typedef struct +{ + uint8_t on = 0; + uint8_t bright_tbl = 0; + uint8_t dimm = 0; + uint8_t impuls_start = 0; + uint32_t impuls_len = 0; +} CHANNEL; + +typedef struct +{ + uint8_t version_major = 0; + uint8_t version_minor = 0; + CHANNEL channel[2]; + uint8_t gate_lock = 0; +} DIMMER; + +struct EXS +{ + uint8_t *buffer = nullptr; // Serial receive buffer + int byte_counter = 0; // Index in serial receive buffer + int cmd_status = 0; + uint8_t power = 0; + uint8_t dimm[2] = {0, 0}; + DIMMER dimmer; +} Exs; + +/* + * Internal Functions + */ + +uint8_t crc8(const uint8_t *p, uint8_t len) +{ + const uint8_t table[] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D}; + + const uint8_t table_rev[] = { + 0x00, 0x70, 0xE0, 0x90, 0xC1, 0xB1, 0x21, 0x51, + 0x83, 0xF3, 0x63, 0x13, 0x42, 0x32, 0xA2, 0xD2}; + + uint8_t offset; + uint8_t temp, crc8_temp; + uint8_t crc8 = 0; + + for (int i = 0; i < len; i++) + { + temp = *(p + i); + offset = temp ^ crc8; + offset >>= 4; + crc8_temp = crc8 & 0x0f; + crc8 = crc8_temp ^ table_rev[offset]; + offset = crc8 ^ temp; + offset &= 0x0f; + crc8_temp = crc8 & 0xf0; + crc8 = crc8_temp ^ table[offset]; + } + return crc8 ^ 0x55; +} + +void ExsSerialSend(const uint8_t data[] = nullptr, uint16_t len = 0) +{ + int retries = 3; + char rc; + +#ifdef EXS_DEBUG + snprintf_P(log_data, sizeof(log_data), PSTR("EXS: Tx Packet: \"")); + for (uint32_t i = 0; i < len; i++) + { + snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, data[i]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + while (retries) + { + retries--; + + ExsSerial->write(data, len); + ExsSerial->flush(); + + // wait for any response + uint32_t snd_time = millis(); + while ((TimePassedSince(snd_time) < EXS_ACK_TIMEOUT) && + (!ExsSerial->available())) + ; + + if (!ExsSerial->available()) + { + // timeout +#ifdef EXS_DEBUG + AddLog_P(LOG_LEVEL_DEBUG, PSTR("ESX: serial send timeout")); +#endif + continue; + } + + rc = ExsSerial->read(); + if (rc == 0xFF) + break; + } +} + +void ExsSendCmd(uint8_t cmd, uint8_t value) +{ + uint8_t buffer[8]; + uint16_t len; + + buffer[0] = 0x7b; + buffer[3] = cmd; + + switch (cmd) + { + case EXS_GATE_1_ON: + case EXS_GATE_1_OFF: + case EXS_DIMM_1_ON: + case EXS_DIMM_1_OFF: + case EXS_GATE_2_ON: + case EXS_GATE_2_OFF: + case EXS_DIMM_2_ON: + case EXS_DIMM_2_OFF: + case EXS_GATES_ON: + case EXS_GATES_OFF: + case EXS_DIMMS_ON: + case EXS_DIMMS_OFF: + case EXS_GET_VALUES: + case EXS_GET_VERSION: + case EXS_RESET: + buffer[2] = 1; + len = 4; + break; + + case EXS_CH_LOCK: + case EXS_DIMM_1_TBL: + case EXS_DIMM_1_VAL: + case EXS_DIMM_2_TBL: + case EXS_DIMM_2_VAL: + buffer[2] = 2; + buffer[4] = value; + len = 5; + break; + } + buffer[1] = crc8(&buffer[3], buffer[2]); + + ExsSerialSend(buffer, len); +} + +uint8_t ExsSetPower(uint8_t device, uint8_t power) +{ + Exs.dimmer.channel[device].dimm = power; + ExsSendCmd(EXS_DIMM_1_ON + 0x10 * device + power ^ 1, 0); +} + +uint8_t ExsSetBri(uint8_t device, uint8_t bri) +{ + Exs.dimmer.channel[device].bright_tbl = bri; + ExsSendCmd(EXS_DIMM_1_TBL + 0x10 * device, bri); +} + +uint8_t ExsSyncState(uint8_t device) +{ +#ifdef EXS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Channel %d Power Want %d, Is %d"), + device, bitRead(Exs.power, device), Exs.dimmer.channel[device].dimm); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Set Channel %d Brightness Want %d, Is %d"), + device, Exs.dimm[device], Exs.dimmer.channel[device].bright_tbl); +#endif + + if (bitRead(Exs.power, device) && + Exs.dimm[device] != Exs.dimmer.channel[device].bright_tbl) { + ExsSetBri(device, Exs.dimm[device]); + } + + if (!Exs.dimm[device]) { + Exs.dimmer.channel[device].dimm = 0; + } else if (Exs.dimmer.channel[device].dimm != bitRead(Exs.power, device)) { + ExsSetPower(device, bitRead(Exs.power, device)); + } +} + +bool ExsSyncState() +{ +#ifdef EXS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Serial %p, Cmd %d"), ExsSerial, Exs.cmd_status); +#endif + + if (!ExsSerial || Exs.cmd_status != 0) + return false; + + ExsSyncState(0); + ExsSyncState(1); +} + +static inline void ExsSetChannelV10(uint8_t channel, const uint8_t *buffer) +{ + Exs.dimmer.channel[channel].on = buffer[0]; + Exs.dimmer.channel[channel].dimm = buffer[1]; + Exs.dimmer.channel[channel].bright_tbl = 0; +} + +static inline void ExsSetChannel(uint8_t channel, const uint8_t *buffer) +{ + Exs.dimmer.channel[channel].on = buffer[0]; + Exs.dimmer.channel[channel].dimm = buffer[1]; + Exs.dimmer.channel[channel].bright_tbl = buffer[2]; +} + +void ExsDebugState() +{ +#ifdef EXS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: MCU v%d.%d, c0: On:%d,Dim:%d,Tbl:%d(%d%%), c1: On:%d,Dim:%d,Tbl:%d(%d%%), ChLock: %d"), + Exs.dimmer.version_major, Exs.dimmer.version_minor, + Exs.dimmer.channel[0].on, Exs.dimmer.channel[0].dimm, + Exs.dimmer.channel[0].bright_tbl, + changeUIntScale(Exs.dimmer.channel[0].bright_tbl, 0, 255, 0, 100), + Exs.dimmer.channel[1].on, Exs.dimmer.channel[1].dimm, + Exs.dimmer.channel[1].bright_tbl, + changeUIntScale(Exs.dimmer.channel[1].bright_tbl, 0, 255, 0, 100), + Exs.dimmer.gate_lock); +#endif +} + +void ExsPacketProcess(void) +{ + uint8_t len = Exs.buffer[1]; + uint8_t cmd = Exs.buffer[2]; + + switch (cmd) + { + case EXS_GET_VALUES: + if (len > 9) + { + Exs.dimmer.version_major = Exs.buffer[3]; + Exs.dimmer.version_minor = Exs.buffer[4]; + ExsSetChannel(0, &Exs.buffer[5]); + ExsSetChannel(1, &Exs.buffer[8]); + Exs.dimmer.gate_lock = Exs.buffer[11]; + } + else + { + Exs.dimmer.version_major = 1; + Exs.dimmer.version_minor = 0; + ExsSetChannel(0, &Exs.buffer[3]); + ExsSetChannel(1, &Exs.buffer[5]); + Exs.dimmer.gate_lock = Exs.buffer[8]; + } + + ExsDebugState(); + ExsSyncState(); + ExsDebugState(); + break; + default: + break; + } +} + +/* + * API Functions + */ +bool ExsModuleSelected(void) +{ + Settings.light_correction = 0; + Settings.flag.mqtt_serial = 0; + Settings.flag3.pwm_multi_channels = 1; + SetSeriallog(LOG_LEVEL_NONE); + + devices_present = +2; + light_type = LT_SERIAL2; + return true; +} + +bool ExsSetChannels(void) +{ +#ifdef EXS_DEBUG + snprintf_P(log_data, sizeof(log_data), PSTR("EXS: SetChannels: \"")); + for (int i = 0; i < XdrvMailbox.data_len; i++) + { + snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, ((uint8_t *)XdrvMailbox.data)[i]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + Exs.dimm[0] = ((uint8_t *)XdrvMailbox.data)[0]; + Exs.dimm[1] = ((uint8_t *)XdrvMailbox.data)[1]; + return ExsSyncState(); +} + +bool ExsSetPower(void) +{ + AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Set Power, Device %d, Power 0x%02x"), + active_device, XdrvMailbox.index); + + Exs.power = XdrvMailbox.index; + return ExsSyncState(); +} + +void EsxMcuStart(void) +{ + int retries = 3; + +#ifdef EXS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Request MCU configuration, PIN %d to Low"), pin[GPIO_EXS_MCU_RESET]); +#endif + + pinMode(pin[GPIO_EXS_MCU_RESET], OUTPUT); + digitalWrite(pin[GPIO_EXS_MCU_RESET], LOW); + + delay(1); // wait 1ms fot the MCU to come online + + while (ExsSerial->available()) + { + // clear in the receive buffer + ExsSerial->read(); + } +} + +void ExsInit(void) +{ +#ifdef EXS_DEBUG + AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Starting Tx %d Rx %d"), pin[GPIO_TXD], pin[GPIO_RXD]); +#endif + + Exs.buffer = (uint8_t *)malloc(EXS_BUFFER_SIZE); + if (Exs.buffer != nullptr) + { + ExsSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2); + if (ExsSerial->begin(9600)) + { + if (ExsSerial->hardwareSerial()) + { + ClaimSerial(); + } + ExsSerial->flush(); + EsxMcuStart(); + ExsSendCmd(EXS_CH_LOCK, 0); + ExsSendCmd(EXS_GET_VALUES, 0); + } + } +} + +void ExsSerialInput(void) +{ + while (ExsSerial->available()) + { + yield(); + uint8_t serial_in_byte = ExsSerial->read(); + + AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Serial In Byte 0x%02x"), serial_in_byte); + + if (Exs.cmd_status == 0 && + serial_in_byte == 0x7B) + { + Exs.cmd_status = 1; + Exs.byte_counter = 0; + } + else if (Exs.byte_counter >= EXS_BUFFER_SIZE) + { + Exs.cmd_status = 0; + } + else if (Exs.cmd_status == 1) + { + Exs.buffer[Exs.byte_counter++] = serial_in_byte; + + if (Exs.byte_counter > 2 && Exs.byte_counter == Exs.buffer[1] + 2) + { + uint8_t crc = crc8(&Exs.buffer[2], Exs.buffer[1]); + + // all read + Exs.cmd_status = 0; + +#ifdef EXS_DEBUG + snprintf_P(log_data, sizeof(log_data), PSTR("EXS: RX Packet: \"")); + for (uint32_t i = 0; i < Exs.byte_counter; i++) + { + snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, Exs.buffer[i]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s\", CRC: 0x%02x"), log_data, crc); + AddLog(LOG_LEVEL_DEBUG_MORE); +#endif + + if (Exs.buffer[0] == crc) + { + ExsSerial->write(0xFF); //send ACK + ExsPacketProcess(); + } + else + { + ExsSerial->write(0x00); //send NO-ACK + } + + } + } + } +} + +/* + * Commands + */ + +#ifdef EXS_MCU_CMNDS + +#define D_PRFX_EXS "Exs" +#define D_CMND_EXS_GATE "Gate" +#define D_CMND_EXS_DIMM "Dimm" +#define D_CMND_EXS_DIMM_TBL "DimmTbl" +#define D_CMND_EXS_DIMM_VAL "DimmVal" +#define D_CMND_EXS_GATES "Gates" +#define D_CMND_EXS_DIMMS "Dimms" +#define D_CMND_EXS_CH_LOCK "ChLock" +#define D_CMND_EXS_STATE "State" + +const char kExsCommands[] PROGMEM = D_PRFX_EXS "|" + D_CMND_EXS_GATE "|" + D_CMND_EXS_DIMM "|" D_CMND_EXS_DIMM_TBL "|" D_CMND_EXS_DIMM_VAL "|" + D_CMND_EXS_GATES "|" D_CMND_EXS_DIMMS "|" D_CMND_EXS_CH_LOCK "|" + D_CMND_EXS_STATE; + +void (* const ExsCommand[])(void) PROGMEM = + { &CmndExsGate, + &CmndExsDimm, &CmndExsDimmTbl, &CmndExsDimmVal, + &CmndExsGates, &CmndExsDimms, &CmndExsChLock, + &CmndExsState }; + +void CmndExsGate(void) +{ + if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && + (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1)) { + ExsSendCmd(EXS_GATE_1_ON + 0x10 * (XdrvMailbox.index - 1) + + XdrvMailbox.payload ^ 1, 0); + } + CmndExsState(); +} + +void CmndExsDimm(void) +{ + if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && + (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1)) { + ExsSendCmd(EXS_DIMM_1_ON + 0x10 * (XdrvMailbox.index - 1) + + XdrvMailbox.payload ^ 1, 0); + } + CmndExsState(); +} + +void CmndExsDimmTbl(void) +{ + if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && + (XdrvMailbox.payload > 0 || XdrvMailbox.payload <= 255)) { + ExsSendCmd(EXS_DIMM_1_TBL + 0x10 * (XdrvMailbox.index - 1), + XdrvMailbox.payload); + } + CmndExsState(); +} + +void CmndExsDimmVal(void) +{ + if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && + (XdrvMailbox.payload > 0 || XdrvMailbox.payload <= 255)) { + ExsSendCmd(EXS_DIMM_1_VAL + 0x10 * (XdrvMailbox.index - 1), + XdrvMailbox.payload); + } + CmndExsState(); +} + +void CmndExsGates(void) +{ + if (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1) { + ExsSendCmd(EXS_GATES_ON + XdrvMailbox.payload ^ 1, 0); + } + CmndExsState(); +} + +void CmndExsDimms(void) +{ + if (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1) { + ExsSendCmd(EXS_DIMMS_ON + XdrvMailbox.payload ^ 1, 0); + } + CmndExsState(); +} + +void CmndExsChLock(void) +{ + if (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1) { + ExsSendCmd(EXS_CH_LOCK, XdrvMailbox.payload); + } + CmndExsState(); +} + +void CmndExsState(void) +{ + ExsSendCmd(EXS_GET_VALUES, 0); + + // wait for data + uint32_t snd_time = millis(); + while ((TimePassedSince(snd_time) < EXS_ACK_TIMEOUT) && + (!ExsSerial->available())) + ; + ExsSerialInput(); + + Response_P(PSTR("{\"" D_CMND_EXS_STATE "\":{")); + ResponseAppend_P(PSTR("\"McuVersion\":\"%d.%d\"," + "\"Channels\":["), + Exs.dimmer.version_major, Exs.dimmer.version_minor); + + for (uint32_t i = 0; i < 2; i++) { + if (i != 0) { + ResponseAppend_P(PSTR(",")); + } + ResponseAppend_P(PSTR("{\"On\":\"%d\"," + "\"BrightProz\":\"%d\"," + "\"BrightTab\":\"%d\"," + "\"Dimm\":\"%d\"}"), + Exs.dimmer.channel[i].on, + changeUIntScale(Exs.dimmer.channel[i].bright_tbl, 0, 255, 0, 100), + Exs.dimmer.channel[i].bright_tbl, + Exs.dimmer.channel[i].dimm); + } + ResponseAppend_P(PSTR("],")); + ResponseAppend_P(PSTR("\"GateLock\":\"%d\""), Exs.dimmer.gate_lock); + ResponseJsonEndEnd(); +} + +#endif + +/* + * Interface + */ + +bool Xdrv30(uint8_t function) +{ + bool result = false; + + if (EXS_DIMMER == my_module_type) + { + switch (function) + { + case FUNC_LOOP: + if (ExsSerial) + ExsSerialInput(); + break; + case FUNC_MODULE_INIT: + result = ExsModuleSelected(); + break; + case FUNC_INIT: + ExsInit(); + break; + case FUNC_SET_DEVICE_POWER: + result = ExsSetPower(); + break; + case FUNC_SET_CHANNELS: + result = ExsSetChannels(); + break; +#ifdef EXS_MCU_CMNDS + case FUNC_COMMAND: + result = DecodeCommand(kExsCommands, ExsCommand); + break; +#endif + } + } + return result; +} + +#endif // USE_EXS_DIMMER +#endif // USE_LIGHT \ No newline at end of file diff --git a/tools/decode-status.py b/tools/decode-status.py index ce20da571..7b8bce742 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -172,7 +172,7 @@ a_features = [[ "USE_BUZZER","USE_RDM6300","USE_IBEACON","USE_SML_M", "USE_INA226","USE_A4988_STEPPER","USE_DDS2382","USE_SM2135", "USE_SHUTTER","USE_PCF8574","USE_DDSU666","USE_DEEPSLEEP", - "USE_SONOFF_SC","USE_SONOFF_RF","USE_SONOFF_L1","", + "USE_SONOFF_SC","USE_SONOFF_RF","USE_SONOFF_L1","USE_EXS_DIMMER", "","","","", "","","","", "","","","",