From 579f68cf2fb70016e794aaf3774bd319d32a7da2 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Sun, 25 Aug 2019 22:10:19 +0100 Subject: [PATCH 1/2] Tuya Dimmer: Add support for dimmers with max 24 New Tuya Dimmer has dim values from 0 to 24. Currently the code expects it to be 0-100 or 0-255. With this change we move the flag to a param and use that to calculate correct dim percentage. This change also makes sure to update settings on version upgrade. --- sonoff/settings.ino | 12 ++++++++++++ sonoff/sonoff.h | 2 +- sonoff/support_command.ino | 1 + sonoff/xdrv_16_tuyadimmer.ino | 18 +++++------------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/sonoff/settings.ino b/sonoff/settings.ino index d29352bbf..158b92319 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -125,6 +125,9 @@ #ifndef ENERGY_OVERTEMP #define ENERGY_OVERTEMP 90 // Overtemp in Celsius #endif +#ifndef TUYA_DIMMER_MAX +#define TUYA_DIMMER_MAX 100 +#endif enum WebColors { COL_TEXT, COL_BACKGROUND, COL_FORM, @@ -761,6 +764,8 @@ void SettingsDefaultSet2(void) // Settings.light_rotation = 0; SettingsDefaultSet_5_8_1(); // Clock color + Settings.param[P_TUYA_DIMMER_MAX] = TUYA_DIMMER_MAX; + // Display SettingsDefaultSet_5_10_1(); // Display settings @@ -1065,6 +1070,13 @@ void SettingsDelta(void) } if (Settings.version < 0x06060007) { memset((char*)&Settings +0xE00, 0x00, sizeof(SYSCFG) -0xE00); + + // Move current tuya dimmer range to the new param. + if (Settings.flag3.tuya_dimmer_range_255) { + Settings.param[P_TUYA_DIMMER_MAX] = 100; + } else { + Settings.param[P_TUYA_DIMMER_MAX] = 255; + } } Settings.version = VERSION; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 59b299218..8bc215c69 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -232,7 +232,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED }; enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38 - P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42 + P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_TUYA_RELAYS, P_OVER_TEMP, P_TUYA_DIMMER_MAX, // SetOption39 .. SetOption43 P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_P1_SMART_METER, DZ_MAX_SENSORS}; diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index 9853ac974..f897e8d80 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -654,6 +654,7 @@ void CmndSetoption(void) #endif #ifdef USE_TUYA_DIMMER case P_TUYA_RELAYS: + case P_TUYA_DIMMER_MAX: restart_flag = 2; // Need a restart to update GUI break; #endif diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyadimmer.ino index a74e418f9..513abf1b4 100644 --- a/sonoff/xdrv_16_tuyadimmer.ino +++ b/sonoff/xdrv_16_tuyadimmer.ino @@ -151,9 +151,7 @@ void LightSerialDuty(uint8_t duty) } if (Settings.flag3.tuya_disable_dimmer == 0) { - if(Settings.flag3.tuya_dimmer_range_255 == 0) { - duty = changeUIntScale(duty, 0, 255, 0, 100); - } + 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); @@ -162,9 +160,7 @@ void LightSerialDuty(uint8_t duty) } else { Tuya.ignore_dim = false; // reset flag if (Settings.flag3.tuya_disable_dimmer == 0) { - if(Settings.flag3.tuya_dimmer_range_255 == 0) { - duty = changeUIntScale(duty, 0, 255, 0, 100); - } + 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 } } @@ -214,20 +210,16 @@ void TuyaPacketProcess(void) 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) { // dim packet + else if (Tuya.buffer[5] == 8) { // Long value packet - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), Tuya.buffer[13]); 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]) { - if(Settings.flag3.tuya_dimmer_range_255 == 0) { - Tuya.new_dim = (uint8_t) Tuya.buffer[13]; - } else { - Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, 255, 0, 100); - } + 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; From 231a1ba1371c545703e4efd879b106ef7c4ff623 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Tue, 27 Aug 2019 10:50:34 +0100 Subject: [PATCH 2/2] Tuya Serial: Add support for power metering Capable Tuya serial devices send power metering data over serial interface. User needs to identify the ids of all power metering functions and set as SetOption44 -> Voltage SetOption45 -> Current SetOption46 -> Power --- sonoff/sonoff.h | 2 +- sonoff/support_command.ino | 3 +++ sonoff/xdrv_16_tuyadimmer.ino | 44 +++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 8bc215c69..c31f1196a 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -232,7 +232,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED }; enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38 - P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_TUYA_RELAYS, P_OVER_TEMP, P_TUYA_DIMMER_MAX, // SetOption39 .. SetOption43 + P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_TUYA_RELAYS, P_OVER_TEMP, P_TUYA_DIMMER_MAX, P_TUYA_VOLTAGE_ID, P_TUYA_CURRENT_ID, P_TUYA_POWER_ID, // SetOption39 .. SetOption46 P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_P1_SMART_METER, DZ_MAX_SENSORS}; diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index f897e8d80..bd07643e9 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -654,6 +654,9 @@ void CmndSetoption(void) #endif #ifdef USE_TUYA_DIMMER case P_TUYA_RELAYS: + case P_TUYA_POWER_ID: + case P_TUYA_CURRENT_ID: + case P_TUYA_VOLTAGE_ID: case P_TUYA_DIMMER_MAX: restart_flag = 2; // Need a restart to update GUI break; diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyadimmer.ino index 513abf1b4..85a4083d6 100644 --- a/sonoff/xdrv_16_tuyadimmer.ino +++ b/sonoff/xdrv_16_tuyadimmer.ino @@ -21,13 +21,12 @@ #ifdef USE_TUYA_DIMMER #define XDRV_16 16 +#define XNRG_08 8 #ifndef TUYA_DIMMER_ID #define TUYA_DIMMER_ID 0 #endif -#define TUYA_POWER_ID 1 - #define TUYA_CMD_HEARTBEAT 0x00 #define TUYA_CMD_QUERY_PRODUCT 0x01 #define TUYA_CMD_MCU_CONF 0x02 @@ -55,6 +54,7 @@ struct TUYA { uint8_t data_len = 0; // Data lenght of command int8_t wifi_state = -2; // Keep MCU wifi-status in sync with WifiState() uint8_t heartbeat_timer = 0; // 10 second heartbeat timer for tuya module + uint32_t lastPowerCheckTime = 0; // Time when last power was checked char *buffer = nullptr; // Serial receive buffer int byte_counter = 0; // Index in serial receive buffer @@ -228,6 +228,25 @@ void TuyaPacketProcess(void) } } } + + 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(); + } + 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]); + } } break; @@ -440,5 +459,26 @@ bool Xdrv16(uint8_t function) return result; } +/*********************************************************************************************\ + * Energy Interface +\*********************************************************************************************/ + +int Xnrg08(uint8_t function) +{ + int result = 0; + if (FUNC_PRE_INIT == function) { + if (Settings.param[P_TUYA_POWER_ID] != 0) { + energy_flg = XNRG_08; + } + if (Settings.param[P_TUYA_CURRENT_ID] == 0) { + Energy.current_available = false; + } + if (Settings.param[P_TUYA_VOLTAGE_ID] == 0) { + Energy.voltage_available = false; + } + } + return result; +} + #endif // USE_TUYA_DIMMER #endif // USE_LIGHT