diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 463ec13cf..287476dd7 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -444,6 +444,10 @@ #define D_CMND_LATITUDE "Latitude" #define D_CMND_LONGITUDE "Longitude" +// Commands xdrv_16_tuyadimmer.ino + +#define D_CMND_TUYA_MCU "TuyaMCU" + // Commands xdrv_23_zigbee.ino #define D_CMND_ZIGBEEZNPSEND "ZigbeeZNPSend" #define D_JSON_ZIGBEEZNPRECEIVED "ZigbeeZNPReceived" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index f55fc774f..a18adc7b7 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -307,7 +307,7 @@ // -- Optional modules ---------------------------- #define USE_BUZZER // Add support for a buzzer (+0k6 code) #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) -#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer +#define USE_TUYA_MCU // Add support for Tuya Serial MCU #define TUYA_DIMMER_ID 0 // Default dimmer Id #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) diff --git a/sonoff/settings.h b/sonoff/settings.h index f326dc529..40be8b25f 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -185,6 +185,14 @@ typedef struct { uint32_t last_return_kWhtotal; } EnergyUsage; + +typedef struct { + uint8_t fnid = 0; + uint8_t dpid = 0; +} TuyaFnidDpidMap; + +const uint8_t MAX_TUYA_FUNCTIONS = 16; + /* struct SYSCFG { unsigned long cfg_holder; // 000 Pre v6 header @@ -364,10 +372,9 @@ struct SYSCFG { uint16_t web_refresh; // 7CC char mems[MAX_RULE_MEMS][10]; // 7CE char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b - uint8_t data8[32]; // E00 - uint16_t data16[16]; // E20 + TuyaFnidDpidMap tuya_fnid_map[MAX_TUYA_FUNCTIONS]; // E00 32 bytes - uint8_t free_e20[448]; // E40 + uint8_t free_e20[480]; // E20 // FFF last location } Settings; diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 4bdae99ff..7c44bf053 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -1096,6 +1096,41 @@ void SettingsDelta(void) Settings.sbaudrate = Settings.ex_sbaudrate * 4; } + if (Settings.version < 0x0606000A) { + uint8_t tuyaindex = 0; + if (Settings.param[P_TUYA_DIMMER_ID] > 0) { + Settings.tuya_fnid_map[tuyaindex].fnid = 21; //TUYA_MCU_FUNC_DIMMER; // Move Tuya Dimmer Id to Map + Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_TUYA_DIMMER_ID]; + tuyaindex++; + } else if (Settings.flag3.tuya_disable_dimmer == 1) { + Settings.tuya_fnid_map[tuyaindex].fnid = 11; //TUYA_MCU_FUNC_REL1; // Create FnID for Switches + Settings.tuya_fnid_map[tuyaindex].dpid = 1; + tuyaindex++; + } + if (Settings.param[P_TUYA_RELAYS] > 0) { + for (uint8_t i = 0 ; i < Settings.param[P_TUYA_RELAYS]; i++) { + Settings.tuya_fnid_map[tuyaindex].fnid = 12 + i; //TUYA_MCU_FUNC_REL2+; // Create FnID for Switches + Settings.tuya_fnid_map[tuyaindex].dpid = i + 2; + tuyaindex++; + } + } + if (Settings.param[P_TUYA_POWER_ID] > 0) { + Settings.tuya_fnid_map[tuyaindex].fnid = 31; //TUYA_MCU_FUNC_POWER; // Move Tuya Power Id to Map + Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_TUYA_POWER_ID]; + tuyaindex++; + } + if (Settings.param[P_TUYA_VOLTAGE_ID] > 0) { + Settings.tuya_fnid_map[tuyaindex].fnid = 33; //TUYA_MCU_FUNC_VOLTAGE; // Move Tuya Voltage Id to Map + Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_TUYA_VOLTAGE_ID]; + tuyaindex++; + } + if (Settings.param[P_TUYA_CURRENT_ID] > 0) { + Settings.tuya_fnid_map[tuyaindex].fnid = 32; //TUYA_MCU_FUNC_CURRENT; // Move Tuya Current Id to Map + Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_TUYA_CURRENT_ID]; + tuyaindex++; + } + + } Settings.version = VERSION; SettingsSave(1); } diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index cc2b8b237..271325da1 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -85,7 +85,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c // -- Optional modules ------------------------- #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) -#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer +#define USE_TUYA_MCU // Add support for Tuya Serial MCU #ifndef TUYA_DIMMER_ID #define TUYA_DIMMER_ID 0 // Default dimmer Id #endif @@ -217,7 +217,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c //#ifndef USE_SONOFF_IFAN #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) //#endif -#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer +#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) #undef ROTARY_V1 // Disable support for MI Desk Lamp @@ -345,7 +345,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c // -- Optional modules ------------------------- #undef USE_BUZZER // Disable support for a buzzer (+0k6 code) #undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code) -#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer +#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) #undef USE_DS18x20 // Disable Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code) @@ -436,7 +436,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c // -- Optional modules ------------------------- #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) -//#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer +//#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) #undef ROTARY_V1 // Disable support for MI Desk Lamp @@ -517,7 +517,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c // -- Optional modules ------------------------- #undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code) -#undef USE_TUYA_DIMMER // Disable support for Tuya Serial Dimmer +#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) #undef ROTARY_V1 // Disable support for MI Desk Lamp diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 85f1a8c8d..cdfe75e23 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -541,7 +541,7 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_SM16716_DAT, // SM16716 DATA GPIO_SM16716_SEL, // SM16716 SELECT #endif // USE_SM16716 -#ifdef USE_TUYA_DIMMER +#ifdef USE_TUYA_MCU GPIO_TUYA_TX, // Tuya Serial interface GPIO_TUYA_RX, // Tuya Serial interface #endif @@ -749,7 +749,7 @@ const uint8_t kModuleNiceList[] PROGMEM = { OBI2, MANZOKU_EU_4, ESP_SWITCH, // Switch Devices -#ifdef USE_TUYA_DIMMER +#ifdef USE_TUYA_MCU TUYA_DIMMER, // Dimmer Devices #endif #ifdef USE_ARMTRONIX_DIMMERS @@ -1728,7 +1728,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On ) 0, 0, 0 }, - { "Tuya Dimmer", // Tuya Dimmer (ESP8266 w/ separate MCU dimmer) + { "Tuya MCU", // Tuya MCU device (ESP8266 w/ separate MCU) // https://www.amazon.com/gp/product/B07CTNSZZ8/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1 GPIO_USER, // Virtual Button (controlled by MCU) GPIO_USER, // GPIO01 MCU serial control diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index e614fbf36..962434a63 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,6 +20,6 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -const uint32_t VERSION = 0x06060009; +const uint32_t VERSION = 0x0606000A; #endif // _SONOFF_VERSION_H_ diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index 1b91dc11b..a11c6b8c1 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -661,7 +661,7 @@ void CmndSetoption(void) IrReceiveUpdateThreshold(); break; #endif -#ifdef USE_TUYA_DIMMER +#ifdef USE_TUYA_MCU case P_TUYA_RELAYS: case P_TUYA_POWER_ID: case P_TUYA_CURRENT_ID: diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 42144d191..8265e4cb9 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -171,7 +171,7 @@ void GetFeatures(void) #ifdef USE_PCA9685 feature_drv2 |= 0x00004000; // xdrv_15_pca9685.ino #endif -#if defined(USE_LIGHT) && defined(USE_TUYA_DIMMER) +#if defined(USE_LIGHT) && defined(USE_TUYA_MCU) feature_drv2 |= 0x00008000; // xdrv_16_tuyadimmer.ino #endif #ifdef USE_RC_SWITCH diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyamcu.ino similarity index 56% rename from sonoff/xdrv_16_tuyadimmer.ino rename to sonoff/xdrv_16_tuyamcu.ino index 608236f4b..61cc584bd 100644 --- a/sonoff/xdrv_16_tuyadimmer.ino +++ b/sonoff/xdrv_16_tuyamcu.ino @@ -1,5 +1,5 @@ /* - xdrv_16_tuyadimmer.ino - Tuya dimmer support for Sonoff-Tasmota + xdrv_16_tuyamcu.ino - Tuya MCU support for Sonoff-Tasmota Copyright (C) 2019 digiblur, Joel Stein and Theo Arends @@ -18,7 +18,7 @@ */ #ifdef USE_LIGHT -#ifdef USE_TUYA_DIMMER +#ifdef USE_TUYA_MCU #define XDRV_16 16 #define XNRG_08 8 @@ -61,10 +61,156 @@ struct TUYA { int byte_counter = 0; // Index in serial receive buffer } Tuya; + +enum TuyaSupportedFunctions { + TUYA_MCU_FUNC_NONE, + TUYA_MCU_FUNC_SWT1 = 1, // Buttons + TUYA_MCU_FUNC_SWT2, + TUYA_MCU_FUNC_SWT3, + TUYA_MCU_FUNC_SWT4, + TUYA_MCU_FUNC_REL1 = 11, // Relays + TUYA_MCU_FUNC_REL2, + TUYA_MCU_FUNC_REL3, + TUYA_MCU_FUNC_REL4, + TUYA_MCU_FUNC_REL5, + TUYA_MCU_FUNC_REL6, + TUYA_MCU_FUNC_REL7, + TUYA_MCU_FUNC_REL8, + TUYA_MCU_FUNC_DIMMER = 21, + TUYA_MCU_FUNC_POWER = 31, + TUYA_MCU_FUNC_CURRENT, + TUYA_MCU_FUNC_VOLTAGE, + TUYA_MCU_FUNC_REL1_INV = 41, // Inverted Relays + TUYA_MCU_FUNC_REL2_INV, + TUYA_MCU_FUNC_REL3_INV, + TUYA_MCU_FUNC_REL4_INV, + TUYA_MCU_FUNC_REL5_INV, + TUYA_MCU_FUNC_REL6_INV, + TUYA_MCU_FUNC_REL7_INV, + TUYA_MCU_FUNC_REL8_INV, + TUYA_MCU_FUNC_LAST = 255 +}; + +const char kTuyaCommand[] PROGMEM = "|" // No prefix + D_CMND_TUYA_MCU; + +void (* const TuyaCommand[])(void) PROGMEM = { + &CmndTuyaMcu +}; + + +/* + +TuyaMcu fnid,dpid + +*/ + +void CmndTuyaMcu(void) { + if (XdrvMailbox.data_len > 0) { + char *p; + uint8_t i = 0; + uint8_t parm[3] = { 0 }; + for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) { + parm[i] = strtoul(str, nullptr, 0); + i++; + } + + if (TuyaFuncIdValid(parm[0])) { + TuyaAddMcuFunc(parm[0], parm[1]); + restart_flag = 2; + } else { + AddLog_P2(LOG_LEVEL_ERROR, PSTR("TYA: TuyaMcu Invalid function id=%d"), parm[0]); + } + + } + + Response_P(PSTR("[")); + bool added = false; + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + if (Settings.tuya_fnid_map[i].fnid != 0) { + if (added) { + ResponseAppend_P(PSTR(",")); + } + ResponseAppend_P(PSTR("{\"fnId\":%d, \"dpId\":%d}" ), Settings.tuya_fnid_map[i].fnid, Settings.tuya_fnid_map[i].dpid); + added = true; + } + } + ResponseAppend_P(PSTR("]")); +} + /*********************************************************************************************\ * Internal Functions \*********************************************************************************************/ +void TuyaAddMcuFunc(uint8_t fnId, uint8_t dpId) { + bool added = false; + + if (fnId == 0 || dpId == 0) { // Delete entry + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + if ((dpId > 0 && Settings.tuya_fnid_map[i].dpid == dpId) || (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].fnid == fnId)) { + Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE; + Settings.tuya_fnid_map[i].dpid = 0; + break; + } + } + } else { // Add or update + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].dpid == 0 || Settings.tuya_fnid_map[i].fnid == fnId || Settings.tuya_fnid_map[i].fnid == 0) { + if (!added) { // Update entry if exisiting entry or add + Settings.tuya_fnid_map[i].fnid = fnId; + Settings.tuya_fnid_map[i].dpid = dpId; + added = true; + } else if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].fnid == fnId) { // Remove existing entry if added to empty place + Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE; + Settings.tuya_fnid_map[i].dpid = 0; + } + } + } + } + UpdateDevices(); +} + +void UpdateDevices() { + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + uint8_t fnId = Settings.tuya_fnid_map[i].fnid; + if (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].dpid > 0) { + + if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { //Relay + bitClear(rel_inverted, fnId - TUYA_MCU_FUNC_REL1); + } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { // Inverted Relay + bitSet(rel_inverted, fnId - TUYA_MCU_FUNC_REL1_INV); + } + + } + } +} + +inline bool TuyaFuncIdValid(uint8_t fnId) { + return (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) || + (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) || + fnId == TUYA_MCU_FUNC_DIMMER || + (fnId >= TUYA_MCU_FUNC_POWER && fnId <= TUYA_MCU_FUNC_VOLTAGE) || + (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV); +} + +uint8_t TuyaGetFuncId(uint8_t dpid) { + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + if (Settings.tuya_fnid_map[i].dpid == dpid) { + return Settings.tuya_fnid_map[i].fnid; + } + } + return TUYA_MCU_FUNC_NONE; +} + +uint8_t TuyaGetDpId(uint8_t fnId) { + for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { + if (Settings.tuya_fnid_map[i].fnid == fnId) { + return Settings.tuya_fnid_map[i].dpid; + } + } + return 0; +} + void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len = 0) { uint8_t checksum = (0xFF + cmd + (payload_len >> 8) + (payload_len & 0xFF)); @@ -131,7 +277,7 @@ bool TuyaSetPower(void) int16_t source = XdrvMailbox.payload; if (source != SRC_SWITCH && TuyaSerial) { // ignore to prevent loop from pushing state from faceplate interaction - TuyaSendBool(active_device, bitRead(rpower, active_device-1)); + TuyaSendBool(active_device, bitRead(rpower, active_device-1) ^ bitRead(rel_inverted, active_device-1)); status = true; } return status; @@ -146,24 +292,26 @@ bool TuyaSetChannels(void) void LightSerialDuty(uint8_t duty) { - if (duty > 0 && !Tuya.ignore_dim && TuyaSerial) { + uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER); + if (duty > 0 && !Tuya.ignore_dim && TuyaSerial && dpid > 0) { if (Settings.flag3.tuya_dimmer_min_limit) { // Enable dimming limit SetOption69: Enabled by default if (duty < 25) { duty = 25; } // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself } - if (Settings.flag3.tuya_disable_dimmer == 0) { duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]); if (Tuya.new_dim != duty) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]); - TuyaSendValue(Settings.param[P_TUYA_DIMMER_ID], duty); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, dpid); + TuyaSendValue(dpid, duty); } } - } else { + } else if (dpid > 0) { Tuya.ignore_dim = false; // reset flag if (Settings.flag3.tuya_disable_dimmer == 0) { duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim skipped value=%d"), duty); // due to 0 or already set } + } else { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Cannot set dimmer. Dimmer Id unknown")); // } } @@ -189,6 +337,7 @@ void TuyaResetWifi(void) void TuyaPacketProcess(void) { char scmnd[20]; + uint8_t fnId = TUYA_MCU_FUNC_NONE; switch (Tuya.buffer[3]) { @@ -201,57 +350,72 @@ void TuyaPacketProcess(void) break; case TUYA_CMD_STATE: - if (Tuya.buffer[5] == 5) { // on/off packet + fnId = TuyaGetFuncId(Tuya.buffer[6]); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: FnId=%d is set for dpId=%d"), fnId, Tuya.buffer[6]); + // if (TuyaFuncIdValid(fnId)) { + if (Tuya.buffer[5] == 5) { // on/off packet - /*if ((power || Settings.light_dimmer > 0) && (power != Tuya.buffer[10])) { - ExecuteCommandPower(1, Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction - }*/ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Device-%d --> MCU State: %s Current State:%s"),Tuya.buffer[6],Tuya.buffer[10]?"On":"Off",bitRead(power, Tuya.buffer[6]-1)?"On":"Off"); - if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[10] != bitRead(power, Tuya.buffer[6]-1))) { - ExecuteCommandPower(Tuya.buffer[6], Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction - } - } - else if (Tuya.buffer[5] == 8) { // Long value packet + if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10]?"On":"Off",bitRead(power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); + if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1))) { + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + } + } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d-Inverted --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10]?"Off":"On",bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); + if (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10] ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + } + } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[10], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); - if (Settings.flag3.tuya_disable_dimmer == 0) { - if (!Settings.param[P_TUYA_DIMMER_ID]) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Autoconfiguring Dimmer ID %d"), Tuya.buffer[6]); - Settings.param[P_TUYA_DIMMER_ID] = Tuya.buffer[6]; - } - if (Settings.param[P_TUYA_DIMMER_ID] == Tuya.buffer[6]) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), Tuya.buffer[13]); - Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, Settings.param[P_TUYA_DIMMER_MAX], 0, 100); - if ((power || Settings.flag3.tuya_apply_o20) && (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) { - Tuya.ignore_dim = true; - - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), Tuya.new_dim ); - ExecuteCommand(scmnd, SRC_SWITCH); + if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[10]) { + SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[10]); + SwitchHandler(1); } } + } + else if (Tuya.buffer[5] == 8) { // Long value packet + if (fnId == TUYA_MCU_FUNC_DIMMER) { + // if (!Settings.param[P_TUYA_DIMMER_ID]) { + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Autoconfiguring Dimmer ID %d"), Tuya.buffer[6]); + // Settings.param[P_TUYA_DIMMER_ID] = Tuya.buffer[6]; + // } + // if (Settings.param[P_TUYA_DIMMER_ID] == Tuya.buffer[6]) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), Tuya.buffer[13]); + Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, Settings.param[P_TUYA_DIMMER_MAX], 0, 100); + if ((power || Settings.flag3.tuya_apply_o20) && (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) { + Tuya.ignore_dim = true; -#ifdef USE_ENERGY_SENSOR - if (Settings.param[P_TUYA_VOLTAGE_ID] == Tuya.buffer[6]) { - Energy.voltage = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Settings.param[P_TUYA_VOLTAGE_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); - } else if (Settings.param[P_TUYA_CURRENT_ID] == Tuya.buffer[6]) { - Energy.current = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 1000; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Settings.param[P_TUYA_CURRENT_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); - } else if (Settings.param[P_TUYA_POWER_ID] == Tuya.buffer[6]) { - Energy.active_power = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Settings.param[P_TUYA_POWER_ID], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); - - if (Tuya.lastPowerCheckTime != 0 && Energy.active_power > 0) { - Energy.kWhtoday += (float)Energy.active_power * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; - EnergyUpdateToday(); + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), Tuya.new_dim ); + ExecuteCommand(scmnd, SRC_SWITCH); + } + // } } - Tuya.lastPowerCheckTime = Rtc.utc_time; - } else if (Settings.param[P_TUYA_DIMMER_ID] != Tuya.buffer[6]){ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Unknown ID=%d"), Tuya.buffer[6]); - } -#endif // USE_ENERGY_SENSOR - } + #ifdef USE_ENERGY_SENSOR + else if (fnId == TUYA_MCU_FUNC_VOLTAGE) { + Energy.voltage = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); + } else if (fnId == TUYA_MCU_FUNC_CURRENT) { + Energy.current = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 1000; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); + } else if (fnId == TUYA_MCU_FUNC_POWER) { + Energy.active_power = (float)(Tuya.buffer[12] << 8 | Tuya.buffer[13]) / 10; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[6], (Tuya.buffer[12] << 8 | Tuya.buffer[13])); + + if (Tuya.lastPowerCheckTime != 0 && Energy.active_power > 0) { + Energy.kWhtoday += (float)Energy.active_power * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; + EnergyUpdateToday(); + } + Tuya.lastPowerCheckTime = Rtc.utc_time; + } + #endif // USE_ENERGY_SENSOR + + } + // } else { + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Unknown FnId=%s for dpId=%s"), fnId, Tuya.buffer[6]); + // } break; case TUYA_CMD_WIFI_RESET: @@ -266,9 +430,9 @@ void TuyaPacketProcess(void) break; case TUYA_CMD_MCU_CONF: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration")); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration Mode=%d"), Tuya.buffer[5]); - if (Tuya.buffer[5] == 2) { + if (Tuya.buffer[5] == 2) { // Processing by ESP module mode uint8_t led1_gpio = Tuya.buffer[6]; uint8_t key1_gpio = Tuya.buffer[7]; bool key1_set = false; @@ -307,21 +471,41 @@ bool TuyaModuleSelected(void) Settings.my_gp.io[3] = GPIO_TUYA_RX; restart_flag = 2; } - if (Settings.flag3.tuya_disable_dimmer == 0) { + + if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) == 0 && TUYA_DIMMER_ID > 0) { + TuyaAddMcuFunc(TUYA_MCU_FUNC_DIMMER, TUYA_DIMMER_ID); + } + + bool relaySet = false; + + devices_present--; + + for (uint8_t i = 0 ; i < MAX_TUYA_FUNCTIONS; i++) { + if ((Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) || + (Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) { + relaySet = true; + devices_present++; + } + } + + if (!relaySet) { + TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1); + devices_present++; + SettingsSaveAll(); + } + + if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) != 0) { light_type = LT_SERIAL1; } else { light_type = LT_BASIC; } + UpdateDevices(); return true; } void TuyaInit(void) { - devices_present += Settings.param[P_TUYA_RELAYS]; // SetOption41 - Add virtual relays if present - if (!Settings.param[P_TUYA_DIMMER_ID]) { - Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID; - } Tuya.buffer = (char*)(malloc(TUYA_BUFFER_SIZE)); if (Tuya.buffer != nullptr) { TuyaSerial = new TasmotaSerial(pin[GPIO_TUYA_RX], pin[GPIO_TUYA_TX], 2); @@ -434,11 +618,11 @@ int Xnrg08(uint8_t function) if (TUYA_DIMMER == my_module_type) { if (FUNC_PRE_INIT == function) { if (!energy_flg) { - if (Settings.param[P_TUYA_POWER_ID] != 0) { - if (Settings.param[P_TUYA_CURRENT_ID] == 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0) { Energy.current_available = false; } - if (Settings.param[P_TUYA_VOLTAGE_ID] == 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0) { Energy.voltage_available = false; } energy_flg = XNRG_08; @@ -486,10 +670,13 @@ bool Xdrv16(uint8_t function) case FUNC_SET_CHANNELS: result = TuyaSetChannels(); break; + case FUNC_COMMAND: + result = DecodeCommand(kTuyaCommand, TuyaCommand); + break; } } return result; } -#endif // USE_TUYA_DIMMER +#endif // USE_TUYA_MCU #endif // USE_LIGHT