From 1a462c986ce5311dec50ef1277b2ce71d0b3aca7 Mon Sep 17 00:00:00 2001 From: Marcus Better Date: Thu, 14 Mar 2024 12:42:52 -0400 Subject: [PATCH] [tuyamcu_v2] Fix suppressed dimmer updates from MQTT (#20950) The driver tried to avoid loops when state updates from the MCU (eg from physical button press) could be reflected back by Tasmota and trigger another MCU command, followed by a state update. It did this by tracking the source of the command in the last_source and last_command_source variables, suppressing the command if either of those was SRC_SWITCH. However this logic is faulty: Since there are two last_source variables to check, a command might reset one of them, but the other would still suppress the update. As it turns out, MQTT commands would only set last_source but not last_command_source. As a result, any dimmer changes via MQTT would be dropped by the driver and not applied to the MCU. Switch functionality (on/off) was still working because those do not rely on last_command_source, only last_source. This change removes the loop detection logic altogether for dimmer updates. This should be safe, because the driver already has the latest dimmer value in its shadow state, and will not try to re-apply a current value, thus breaking the loop. This patch has been tested with several CE-WF500D dimmers which had this problem. --- tasmota/tasmota.ino | 1 - tasmota/tasmota_support/support_command.ino | 1 - .../tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino | 16 ++++++---------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index ec4a1b93d..e0e57788f 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -401,7 +401,6 @@ struct TasmotaGlobal_t { 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 last_command_source; // Last command source uint8_t shutters_present; // Number of actual define shutters uint8_t discovery_counter; // Delayed discovery counter uint8_t power_on_delay; // Delay relay power on to reduce power surge (SetOption47) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 21a7a21cf..4f8e1f960 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -338,7 +338,6 @@ void ExecuteCommand(const char *cmnd, uint32_t source) // cmnd: "var1=1" = stopic "var1" and svalue "=1" SHOW_FREE_MEM(PSTR("ExecuteCommand")); ShowSource(source); - TasmotaGlobal.last_command_source = source; const char *pos = cmnd; while (*pos && isspace(*pos)) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino index 850bb6854..9d4364552 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino @@ -1245,11 +1245,12 @@ bool TuyaSetPower(void) uint8_t dev = TasmotaGlobal.active_device-1; uint8_t value = bitRead(rpower, dev) ^ bitRead(TasmotaGlobal.rel_inverted, dev); - if (source != SRC_SWITCH && TuyaSerial && dpid) { // ignore to prevent loop from pushing state from faceplate interaction + // Ignore the command if the source is SRC_SWITCH, to prevent loop from pushing state + // from faceplate interaction. (This is probably unnecessary, as we store the latest state + // and will not update it with the same value.) + if (source != SRC_SWITCH && TuyaSerial && dpid) { TuyaSendBool(dpid, value); AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: post rpower%d v%d dp%d s%d d%d"), rpower, value, dpid, source, dev); - // no longer needed as commands wait for ack. - //delay(20); // Hack when power is off and dimmer is set then both commands go too soon to Serial out. status = true; } else { AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: rpower%d v%d dp%d ignored s%d d%d"), rpower, value, dpid, source, dev); @@ -1265,11 +1266,6 @@ bool TuyaSetChannels(void) char hex_char[15]; bool noupd = false; - if ((SRC_SWITCH == TasmotaGlobal.last_source) || (SRC_SWITCH == TasmotaGlobal.last_command_source)) { - AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: setchan disbl SRC_SWITCH")); - // but pretend we did set them - return true; - } AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: setchan")); bool LightMode = TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0; @@ -1619,12 +1615,12 @@ void TuyaProcessRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen) AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1 + 1, value?"On":"Off",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)) { if (!value) { PowerOff = true; } - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, value, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, value, SRC_SWITCH); } } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-Inv-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1_INV + 1, value?"Off":"On",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, value ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, value ^ 1, SRC_SWITCH); if (value) { PowerOff = true; } } } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) {