From d6fc62e3769dc1655cce63445f08d933a6289ad2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:17:53 +0100 Subject: [PATCH] Add support for Linkind dimmer Add support for Linkind dimmer as GPIO ``Option A6`` (#14004) --- CHANGELOG.md | 2 ++ RELEASENOTES.md | 2 ++ tasmota/support.ino | 5 +++ tasmota/support_tasmota.ino | 5 +++ tasmota/tasmota.ino | 1 + tasmota/tasmota_configurations_ESP32.h | 2 +- tasmota/tasmota_globals.h | 1 - tasmota/tasmota_template.h | 44 +++++++++++++++++++------- tasmota/xdrv_04_light.ino | 11 +++++-- tasmota/xdrv_35_pwm_dimmer.ino | 32 +++++++++++++------ 10 files changed, 80 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbd73a4ea..c3d105e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ All notable changes to this project will be documented in this file. - Solax X1 modbus RTS support and offline status (#14305) - DDP schemes for light and WS2812 (#14017) - ESP32 single binary firmware (#14239) +- ESP32 support for USE_PWM_DIMMER as GPIO ``Option E1`` +- Support for Linkind dimmer as GPIO ``Option A6`` (#14004) ### Changed - PubSubClient library from v2.8.12 to v2.8.13 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a6e79cf58..01537aecd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -105,6 +105,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Command ``SSerialConfig `` to change Serial Bridge configuration - Command ``SspmMap 2,1,..`` to map Sonoff SPM scanned module to physical module [#14281](https://github.com/arendst/Tasmota/issues/14281) - PWM Dimmer two button support [#13993](https://github.com/arendst/Tasmota/issues/13993) +- Support for Linkind dimmer as GPIO ``Option A6`` [#14004](https://github.com/arendst/Tasmota/issues/14004) - DDP schemes for light and WS2812 [#14017](https://github.com/arendst/Tasmota/issues/14017) - Device Group Send full status item [#14045](https://github.com/arendst/Tasmota/issues/14045) - Support for MAX7219 Dot Matrix displays [#14091](https://github.com/arendst/Tasmota/issues/14091) @@ -114,6 +115,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - ESP32 single binary firmware [#14239](https://github.com/arendst/Tasmota/issues/14239) - ESP32 support for TuyaMcu - ESP32 Berry features +- ESP32 support for USE_PWM_DIMMER as GPIO ``Option E1`` ### Breaking Changed diff --git a/tasmota/support.ino b/tasmota/support.ino index 7f60fa7b9..d28922aa5 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1523,6 +1523,11 @@ void ModuleDefault(uint32_t module) void SetModuleType(void) { TasmotaGlobal.module_type = (USER_MODULE == Settings->module) ? Settings->user_template_base : Settings->module; +#ifdef ESP32 + if (TasmotaGlobal.emulated_module_type) { + TasmotaGlobal.module_type = TasmotaGlobal.emulated_module_type; + } +#endif } bool FlashPin(uint32_t pin) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 9bd9169a7..e85c280ed 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1781,6 +1781,11 @@ void GpioInit(void) mpin -= (AGPIO(GPIO_KEY1_INV_NP) - AGPIO(GPIO_KEY1)); } #ifdef ESP32 + else if ((mpin >= AGPIO(GPIO_OPTION_E)) && (mpin < (AGPIO(GPIO_OPTION_E) + MAX_OPTIONS_E))) { + TasmotaGlobal.emulated_module_type = pgm_read_byte(kModuleEmulationList + (mpin - AGPIO(GPIO_OPTION_A))); + SetModuleType(); + mpin = GPIO_NONE; + } else if ((mpin >= AGPIO(GPIO_SWT1_PD)) && (mpin < (AGPIO(GPIO_SWT1_PD) + MAX_SWITCHES))) { SwitchPulldownFlag(mpin - AGPIO(GPIO_SWT1_PD)); mpin -= (AGPIO(GPIO_SWT1_PD) - AGPIO(GPIO_SWT1)); diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 591b8b4f4..ba38c7779 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -181,6 +181,7 @@ struct TasmotaGlobal_t { uint8_t syslog_level; // Current copy of Settings->syslog_level uint8_t templog_level; // Temporary log level to be used by HTTP cm and Telegram uint8_t module_type; // Current copy of Settings->module or user template type + uint8_t emulated_module_type; // Emulated module type as requested by ESP32 uint8_t last_source; // Last command source uint8_t shutters_present; // Number of actual define shutters uint8_t discovery_counter; // Delayed discovery counter diff --git a/tasmota/tasmota_configurations_ESP32.h b/tasmota/tasmota_configurations_ESP32.h index 74ed07d32..ece3096c8 100644 --- a/tasmota/tasmota_configurations_ESP32.h +++ b/tasmota/tasmota_configurations_ESP32.h @@ -391,7 +391,7 @@ #undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer //#define USE_HOTPLUG // Add support for sensor HotPlug //#undef USE_DEVICE_GROUPS // Disable support for device groups (+5k6 code) -#undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) +//#undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) #undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) #undef USE_SHELLY_DIMMER // Disable support for Shelly Dimmer (+3k code) diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index b7067ab94..15ec22abe 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -133,7 +133,6 @@ String EthernetMacAddress(void); #undef FIRMWARE_MINIMAL // Minimal is not supported as not needed // Hardware has no ESP32 -#undef USE_PWM_DIMMER #undef USE_EXS_DIMMER #undef USE_ARMTRONIX_DIMMERS #undef USE_SONOFF_RF diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 26b6970c0..8f9f2b863 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -178,6 +178,7 @@ enum UserSelectablePins { GPIO_HEARTBEAT, GPIO_HEARTBEAT_INV, GPIO_SHIFT595_SRCLK, GPIO_SHIFT595_RCLK, GPIO_SHIFT595_OE, GPIO_SHIFT595_SER, // 74x595 Shift register GPIO_SOLAXX1_RTS, // Solax Inverter Serial interface + GPIO_OPTION_E, // Emulated module GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -185,7 +186,7 @@ enum ProgramSelectablePins { GPIO_USER, // User configurable needs to be 2047 GPIO_MAX }; -#define MAX_OPTIONS_A 5 // Increase if more bits are used from GpioOptionABits +#define MAX_OPTIONS_A 6 // Increase if more bits are used from GpioOptionABits typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption @@ -195,7 +196,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t udisplay_driver : 1; // bit 2 (v9.3.1.2) - Option_A3 - (Display) Universal display driver uint32_t enable_ccloader : 1; // bit 3 (v9.4.0.5) - Option_A4 - (Zigbee) Enable CCLoader using Zigbee Rx/Tx/Rst Gpios uint32_t rotary_mi_desk : 1; // bit 4 (v9.5.0.5) - Option_A5 - (Rotary) Enable Mi Desk emulation - uint32_t spare05 : 1; // bit 5 + uint32_t linkind_support : 1; // bit 5 (v2022.01.1) - Option_A6 - (Light) LinkInd support uint32_t spare06 : 1; // bit 6 uint32_t spare07 : 1; // bit 7 uint32_t spare08 : 1; // bit 8 @@ -225,6 +226,23 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu }; } GpioOptionABits; +enum SupportedEmulationModules { + SONOFF_BASIC, SONOFF_RF, SONOFF_SV, SONOFF_TH, SONOFF_DUAL, SONOFF_POW, SONOFF_4CH, SONOFF_S2X, SLAMPHER, SONOFF_TOUCH, + SONOFF_LED, CH1, CH4, MOTOR, ELECTRODRAGON, EXS_RELAY, WION, WEMOS_DUMMY, SONOFF_DEV, H801, + SONOFF_SC, SONOFF_BN, SONOFF_4CHPRO, HUAFAN_SS, SONOFF_BRIDGE, SONOFF_B1, AILIGHT, SONOFF_T11, SONOFF_T12, SONOFF_T13, + SUPLA1, WITTY, YUNSHAN, MAGICHOME, LUANIHVIO, KMC_70011, ARILUX_LC01, ARILUX_LC11, SONOFF_DUAL_R2, ARILUX_LC06, + SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH, + OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4, + OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1, + SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, SONOFF_ZB_BRIDGE, + MAXMODULE_EMULATION }; + +#define MAX_OPTIONS_E 1 // Increase if more emulated modules are supported from kModuleEmulationList + +const uint8_t kModuleEmulationList[] PROGMEM = { + PWM_DIMMER // (v2022.01.1) - Option_E1 - (Light) USE_PWM_DIMMER support +}; + // Text in webpage Module Parameters and commands GPIOS and GPIO const char kSensorNames[] PROGMEM = D_SENSOR_NONE "|" @@ -376,6 +394,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_HEARTBEAT "|" D_SENSOR_HEARTBEAT "_i|" D_GPIO_SHIFT595_SRCLK "|" D_GPIO_SHIFT595_RCLK "|" D_GPIO_SHIFT595_OE "|" D_GPIO_SHIFT595_SER "|" D_SENSOR_SOLAXX1_RTS "|" + D_SENSOR_OPTION " E|" ; const char kSensorNamesFixed[] PROGMEM = @@ -390,6 +409,9 @@ const char kSensorNamesFixed[] PROGMEM = const uint16_t kGpioNiceList[] PROGMEM = { GPIO_NONE, // Not used AGPIO(GPIO_OPTION_A) + MAX_OPTIONS_A, // Device specific options +#ifdef ESP32 + AGPIO(GPIO_OPTION_E) + MAX_OPTIONS_E, // Device module emulation +#endif AGPIO(GPIO_KEY1) + MAX_KEYS, // Buttons AGPIO(GPIO_KEY1_NP) + MAX_KEYS, #ifdef ESP32 @@ -1143,8 +1165,8 @@ typedef struct MYTMPLT { #define USER_MODULE 255 -// Supported hardware modules -enum SupportedModules { +// Supported ESP8266 hardware modules +enum SupportedModulesESP8266 { SONOFF_BASIC, SONOFF_RF, SONOFF_SV, SONOFF_TH, SONOFF_DUAL, SONOFF_POW, SONOFF_4CH, SONOFF_S2X, SLAMPHER, SONOFF_TOUCH, SONOFF_LED, CH1, CH4, MOTOR, ELECTRODRAGON, EXS_RELAY, WION, WEMOS, SONOFF_DEV, H801, SONOFF_SC, SONOFF_BN, SONOFF_4CHPRO, HUAFAN_SS, SONOFF_BRIDGE, SONOFF_B1, AILIGHT, SONOFF_T11, SONOFF_T12, SONOFF_T13, @@ -2556,7 +2578,7 @@ const mytmplt8285 kModules8285[TMP_MAXMODULE_8266 - TMP_WEMOS] PROGMEM = { #define USER_MODULE 255 // Supported hardware modules -enum SupportedModules { +enum SupportedModulesESP32C3 { WEMOS, MAXMODULE }; @@ -2570,7 +2592,7 @@ const char kModuleNames[] PROGMEM = "ESP32C3|" ; -// !!! Update this list in the same order as SupportedModules !!! +// !!! Update this list in the same order as SupportedModulesESP32C3 !!! const mytmplt kModules[] PROGMEM = { { // Generic ESP32C3 device AGPIO(GPIO_USER), // 0 IO GPIO0, ADC1_CH0, XTAL_32K_P @@ -2606,13 +2628,13 @@ const mytmplt kModules[] PROGMEM = { #elif defined(CONFIG_IDF_TARGET_ESP32S2) /********************************************************************************************\ - * ESP32-C3 Module templates + * ESP32-S2 Module templates \********************************************************************************************/ #define USER_MODULE 255 // Supported hardware modules -enum SupportedModules { +enum SupportedModulesESP32S2 { WEMOS, MAXMODULE }; @@ -2626,7 +2648,7 @@ const char kModuleNames[] PROGMEM = "ESP32S2|" ; -// !!! Update this list in the same order as SupportedModules !!! +// !!! Update this list in the same order as SupportedModulesESP32S2 !!! const mytmplt kModules[] PROGMEM = { { // Generic ESP32C3 device AGPIO(GPIO_USER), // 0 IO GPIO0, RTC_GPIO0, Strapping @@ -2692,7 +2714,7 @@ const mytmplt kModules[] PROGMEM = { #define USER_MODULE 255 // Supported hardware modules -enum SupportedModules { +enum SupportedModulesESP32 { WEMOS, ESP32_CAM_AITHINKER, ODROID_GO, @@ -2748,7 +2770,7 @@ const char kModuleNames[] PROGMEM = #endif // USE_M5STACK_CORE2 ; -// !!! Update this list in the same order as SupportedModules !!! +// !!! Update this list in the same order as SupportedModulesESP32 !!! const mytmplt kModules[] PROGMEM = { { // WEMOS - Espressif ESP32-DevKitC - Any ESP32 device like WeMos and NodeMCU hardware (ESP32) AGPIO(GPIO_USER), // 0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 4a46c3ae2..34e920eac 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1060,11 +1060,9 @@ bool LightModuleInit(void) } #endif // ESP8266 #ifdef USE_PWM_DIMMER -#ifdef USE_DEVICE_GROUPS else if (PWM_DIMMER == TasmotaGlobal.module_type) { TasmotaGlobal.light_type = Settings->pwm_dimmer_cfg.pwm_count + 1; } -#endif // USE_DEVICE_GROUPS #endif // USE_PWM_DIMMER if (TasmotaGlobal.light_type > LT_BASIC) { @@ -2091,6 +2089,15 @@ void LightSetOutputs(const uint16_t *cur_col_10) { if (TasmotaGlobal.light_type < LT_PWM6) { // only for direct PWM lights, not for Tuya, Armtronix... #ifdef USE_PWM_DIMMER uint16_t max_col = 0; +#ifdef USE_I2C + if (TasmotaGlobal.gpio_optiona.linkind_support) { // Option_A6 + uint8_t val = change10to8(cur_col_10[Light.pwm_offset] > 0 ? changeUIntScale(cur_col_10[Light.pwm_offset], 0, Settings->pwm_range, Light.pwm_min, Light.pwm_max) : 0); + max_col = val; + uint16_t chk = 65403 - val; + uint8_t buf[] = { 0x09, 0x50, 0x01, val, 0x00, 0x00, (uint8_t)(chk >> 8), (uint8_t)(chk & 0xff) }; + I2cWriteBuffer(0x50, 0x2A, buf, sizeof(buf)); + } else +#endif // USE_I2C #endif // USE_PWM_DIMMER for (uint32_t i = 0; i < (Light.subtype - Light.pwm_offset); i++) { uint16_t cur_col = cur_col_10[i + Light.pwm_offset]; diff --git a/tasmota/xdrv_35_pwm_dimmer.ino b/tasmota/xdrv_35_pwm_dimmer.ino index aad092643..803751500 100644 --- a/tasmota/xdrv_35_pwm_dimmer.ino +++ b/tasmota/xdrv_35_pwm_dimmer.ino @@ -29,6 +29,9 @@ * https://www.amazon.com/dp/B07K67D43J * https://www.amazon.com/dp/B07TTGFWFM * +* Template for Linkind device +* {"NAME":"ESP32-Linkind","GPIO":[6213,8448,0,0,640,0,0,0,0,288,0,0,0,0,0,0,0,608,0,0,0,544,0,0,0,0,0,0,33,32,0,0,0,0,0,0],"FLAG":0,"BASE":1} +* \*********************************************************************************************/ #define XDRV_35 35 @@ -126,7 +129,11 @@ void PWMModulePreInit(void) device_group_count = button_count; // If no relay or PWM is defined, all buttons control remote devices. - if (!PinUsed(GPIO_REL1) && !PinUsed(GPIO_PWM1)) { + if (!PinUsed(GPIO_REL1) && !PinUsed(GPIO_PWM1) +#ifdef USE_I2C + && !PinUsed(GPIO_I2C_SCL) +#endif // USE_I2C + ) { first_device_group_is_local = false; // Back out the changes made in the light module under the assumtion we have a relay or PWM. @@ -165,13 +172,16 @@ void PWMDimmerSetBrightnessLeds(int32_t bri) bri = ((bri == -2 && Settings->flag4.led_timeout) || !Light.power ? 0 : light_state.getBri()); if (!bri || !Settings->flag4.led_timeout) led_timeout_seconds = 0; } - uint32_t step = 256 / (leds + 1); // Turn the LED's on/off. - uint32_t level = 0; + uint32_t step = 256 / (leds + 1); + int32_t level = 0; + if (TasmotaGlobal.gpio_optiona.linkind_support) { + step = 256 / leds; + level = -step; + } led = -1; mask = 0; - uint16_t pwm_led_bri = 0; for (uint32_t count = 0; count < leds; count++) { level += step; for (;;) { @@ -180,8 +190,12 @@ void PWMDimmerSetBrightnessLeds(int32_t bri) if (!mask) mask = 1; if (Settings->ledmask & mask) break; } - pwm_led_bri = changeUIntScale((bri > level ? bri - level : 0), 0, step, 0, Settings->pwm_range); - analogWrite(Pin(GPIO_LED1, led), bitRead(TasmotaGlobal.led_inverted, led) ? Settings->pwm_range - pwm_led_bri : pwm_led_bri); + if (TasmotaGlobal.gpio_optiona.linkind_support) { + SetLedPowerIdx(led, bri > level); + } else { + uint16_t pwm_led_bri = changeUIntScale((bri > level ? bri - level : 0), 0, step, 0, Settings->pwm_range); + analogWrite(Pin(GPIO_LED1, led), bitRead(TasmotaGlobal.led_inverted, led) ? Settings->pwm_range - pwm_led_bri : pwm_led_bri); + } } } } @@ -450,15 +464,13 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed) if (invert_power_button_bri_direction) { invert_power_button_bri_direction = false; #ifdef USE_PWM_DIMMER_REMOTE - if (active_remote_pwm_dimmer) + if (active_remote_pwm_dimmer) { active_remote_pwm_dimmer->power_button_increases_bri ^= 1; - else + } else #endif // USE_PWM_DIMMER_REMOTE power_button_increases_bri ^= 1; -#ifdef USE_PWM_DIMMER_REMOTE dgr_item = DGR_ITEM_FLAGS; state_updated = true; -#endif // USE_PWM_DIMMER_REMOTE } }