[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.
This commit is contained in:
Marcus Better 2024-03-14 12:42:52 -04:00 committed by GitHub
parent cc8614da9c
commit 1a462c986c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 6 additions and 12 deletions

View File

@ -401,7 +401,6 @@ struct TasmotaGlobal_t {
uint8_t module_type; // Current copy of Settings->module or user template type 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 emulated_module_type; // Emulated module type as requested by ESP32
uint8_t last_source; // Last command source 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 shutters_present; // Number of actual define shutters
uint8_t discovery_counter; // Delayed discovery counter uint8_t discovery_counter; // Delayed discovery counter
uint8_t power_on_delay; // Delay relay power on to reduce power surge (SetOption47) uint8_t power_on_delay; // Delay relay power on to reduce power surge (SetOption47)

View File

@ -338,7 +338,6 @@ void ExecuteCommand(const char *cmnd, uint32_t source)
// cmnd: "var1=1" = stopic "var1" and svalue "=1" // cmnd: "var1=1" = stopic "var1" and svalue "=1"
SHOW_FREE_MEM(PSTR("ExecuteCommand")); SHOW_FREE_MEM(PSTR("ExecuteCommand"));
ShowSource(source); ShowSource(source);
TasmotaGlobal.last_command_source = source;
const char *pos = cmnd; const char *pos = cmnd;
while (*pos && isspace(*pos)) { while (*pos && isspace(*pos)) {

View File

@ -1245,11 +1245,12 @@ bool TuyaSetPower(void)
uint8_t dev = TasmotaGlobal.active_device-1; uint8_t dev = TasmotaGlobal.active_device-1;
uint8_t value = bitRead(rpower, dev) ^ bitRead(TasmotaGlobal.rel_inverted, dev); 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); 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); 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; status = true;
} else { } else {
AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: rpower%d v%d dp%d ignored s%d d%d"), rpower, value, dpid, source, dev); 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]; char hex_char[15];
bool noupd = false; 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")); AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: setchan"));
bool LightMode = TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0; 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"); 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 != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)) {
if (!value) { PowerOff = true; } 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) { } 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"); 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) { 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; } if (value) { PowerOff = true; }
} }
} else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) {