Add support for Linkind dimmer

Add support for Linkind dimmer as GPIO ``Option A6`` (#14004)
This commit is contained in:
Theo Arends 2022-01-07 16:17:53 +01:00
parent ab01d479ee
commit d6fc62e376
10 changed files with 80 additions and 25 deletions

View File

@ -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

View File

@ -105,6 +105,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- Command ``SSerialConfig <serialconfig>`` 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

View File

@ -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)

View File

@ -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));

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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];

View File

@ -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
}
}