From 4ee1db93944a204fd13fcfad13d54ca3053cf6fc Mon Sep 17 00:00:00 2001 From: Andrei Date: Sat, 20 Apr 2024 14:43:02 +0300 Subject: [PATCH 1/3] Added support for Energy saving mode (airState.powerSave.basic) (issue #714) (#524) --- .../smartthinq_sensors/switch.py | 7 +++++ .../smartthinq_sensors/wideq/const.py | 1 + .../smartthinq_sensors/wideq/devices/ac.py | 30 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 21f4d1e0..5e2461cd 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -98,6 +98,13 @@ class ThinQSwitchEntityDescription(SwitchEntityDescription): turn_off_fn=lambda x: x.device.set_mode_airclean(False), turn_on_fn=lambda x: x.device.set_mode_airclean(True), ), + ThinQSwitchEntityDescription( + key=AirConditionerFeatures.MODE_POWER_SAVE, + name="Energy saving", + icon="mdi:leaf-circle-outline", + turn_off_fn=lambda x: x.device.set_mode_power_save(False), + turn_on_fn=lambda x: x.device.set_mode_power_save(True), + ), ThinQSwitchEntityDescription( key=AirConditionerFeatures.MODE_JET, name="Jet mode", diff --git a/custom_components/smartthinq_sensors/wideq/const.py b/custom_components/smartthinq_sensors/wideq/const.py index 23fe0b51..92232b1f 100644 --- a/custom_components/smartthinq_sensors/wideq/const.py +++ b/custom_components/smartthinq_sensors/wideq/const.py @@ -39,6 +39,7 @@ class AirConditionerFeatures(StrEnum): FILTER_MAIN_USE = "filter_main_use" LIGHTING_DISPLAY = "lighting_display" MODE_AIRCLEAN = "mode_airclean" + MODE_POWER_SAVE = "mode_power_save" MODE_AWHP_SILENT = "mode_awhp_silent" MODE_JET = "mode_jet" PM1 = "pm1" diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index ba7e2217..dc4d354f 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -34,6 +34,7 @@ SUPPORT_JET_COOL = [SUPPORT_RAC_SUBMODE, "@AC_MAIN_WIND_MODE_COOL_JET_W"] SUPPORT_JET_HEAT = [SUPPORT_RAC_SUBMODE, "@AC_MAIN_WIND_MODE_HEAT_JET_W"] SUPPORT_AIRCLEAN = [SUPPORT_RAC_MODE, "@AIRCLEAN"] +SUPPORT_POWER_SAVE = [SUPPORT_RAC_MODE, "@ENERGYSAVING"] SUPPORT_HOT_WATER = [SUPPORT_PAC_MODE, ["@HOTWATER", "@HOTWATER_ONLY"]] SUPPORT_LIGHT_SWITCH = [SUPPORT_LIGHT, "@RAC_88_DISPLAY_CONTROL"] SUPPORT_LIGHT_INV_SWITCH = [SUPPORT_LIGHT, "@BRIGHTNESS_CONTROL"] @@ -71,6 +72,7 @@ STATE_POWER = [STATE_POWER_V1, "airState.energy.onCurrent"] STATE_HUMIDITY = ["SensorHumidity", "airState.humidity.current"] STATE_MODE_AIRCLEAN = ["AirClean", "airState.wMode.airClean"] +STATE_MODE_POWER_SAVE = ["PowerSave", "airState.powerSave.basic"] STATE_MODE_JET = ["Jet", "airState.wMode.jet"] STATE_LIGHTING_DISPLAY = ["DisplayControl", "airState.lightingState.displayControl"] STATE_AIRSENSORMON = ["SensorMon", "airState.quality.sensorMon"] @@ -102,6 +104,7 @@ CMD_STATE_WDIR_VSWING = [CTRL_WIND_DIRECTION, "Set", STATE_WDIR_VSWING] CMD_STATE_DUCT_ZONES = [CTRL_MISC, "Set", [DUCT_ZONE_V1, "airState.ductZone.control"]] CMD_STATE_MODE_AIRCLEAN = [CTRL_BASIC, "Set", STATE_MODE_AIRCLEAN] +CMD_STATE_MODE_POWER_SAVE = [CTRL_BASIC, "Set", STATE_MODE_POWER_SAVE] CMD_STATE_MODE_JET = [CTRL_BASIC, "Set", STATE_MODE_JET] CMD_STATE_LIGHTING_DISPLAY = [CTRL_BASIC, "Set", STATE_LIGHTING_DISPLAY] CMD_RESERVATION_SLEEP_TIME = [CTRL_BASIC, "Set", STATE_RESERVATION_SLEEP_TIME] @@ -588,6 +591,11 @@ def is_mode_airclean_supported(self): """Return if AirClean mode is supported.""" return self._is_mode_supported(SUPPORT_AIRCLEAN) + @cached_property + def is_mode_power_save_supported(self): + """Return if PowerSave mode is supported.""" + return self._is_mode_supported(SUPPORT_POWER_SAVE) + @cached_property def supported_ligth_modes(self): """Return light switch modes supported.""" @@ -749,6 +757,16 @@ async def set_mode_airclean(self, status: bool): mode = self.model_info.enum_value(keys[2], mode_key) await self.set(keys[0], keys[1], key=keys[2], value=mode) + async def set_mode_power_save(self, status: bool): + """Set the PowerSave mode on or off.""" + if not self.is_mode_power_save_supported: + raise ValueError("PowerSave mode not supported") + + keys = self._get_cmd_keys(CMD_STATE_MODE_POWER_SAVE) + mode_key = MODE_ON if status else MODE_OFF + mode = self.model_info.enum_value(keys[2], mode_key) + await self.set(keys[0], keys[1], key=keys[2], value=mode) + async def set_mode_jet(self, status: bool): """Set the Jet mode on or off.""" if self.supported_mode_jet == JetModeSupport.NONE: @@ -1187,6 +1205,17 @@ def mode_airclean(self): status = value == MODE_AIRCLEAN_ON return self._update_feature(AirConditionerFeatures.MODE_AIRCLEAN, status, False) + @property + def mode_power_save(self): + """Return PowerSave Mode status.""" + if not self._device.is_mode_power_save_supported: + return None + key = self._get_state_key(STATE_MODE_POWER_SAVE) + if (value := self.lookup_enum(key, True)) is None: + return None + status = value == MODE_ON + return self._update_feature(AirConditionerFeatures.MODE_POWER_SAVE, status, False) + @property def mode_jet(self): """Return Jet Mode status.""" @@ -1396,6 +1425,7 @@ def _update_features(self): self.pm25, self.pm1, self.mode_airclean, + self.mode_power_save, self.mode_jet, self.lighting_display, self.water_in_current_temp, From 00e414538b75b25ab7426bb45f5c6cf7751895d5 Mon Sep 17 00:00:00 2001 From: Andrei Date: Fri, 10 May 2024 17:25:51 +0300 Subject: [PATCH 2/3] Added switch for Autodry feature - it only displays the state, it doesn't change it --- .../smartthinq_sensors/switch.py | 7 +++++ .../smartthinq_sensors/wideq/const.py | 1 + .../smartthinq_sensors/wideq/devices/ac.py | 30 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 5e2461cd..1980ddf6 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -98,6 +98,13 @@ class ThinQSwitchEntityDescription(SwitchEntityDescription): turn_off_fn=lambda x: x.device.set_mode_airclean(False), turn_on_fn=lambda x: x.device.set_mode_airclean(True), ), + ThinQSwitchEntityDescription( + key=AirConditionerFeatures.MODE_REMOVE_MOISTURE, + name="Remove moisture", + icon="mdi:fan", + turn_off_fn=lambda x: x.device.set_mode_remove_moisture(False), + turn_on_fn=lambda x: x.device.set_mode_remove_moisture(True), + ), ThinQSwitchEntityDescription( key=AirConditionerFeatures.MODE_POWER_SAVE, name="Energy saving", diff --git a/custom_components/smartthinq_sensors/wideq/const.py b/custom_components/smartthinq_sensors/wideq/const.py index 92232b1f..9bfec432 100644 --- a/custom_components/smartthinq_sensors/wideq/const.py +++ b/custom_components/smartthinq_sensors/wideq/const.py @@ -39,6 +39,7 @@ class AirConditionerFeatures(StrEnum): FILTER_MAIN_USE = "filter_main_use" LIGHTING_DISPLAY = "lighting_display" MODE_AIRCLEAN = "mode_airclean" + MODE_REMOVE_MOISTURE = "mode_remove_moisture" MODE_POWER_SAVE = "mode_power_save" MODE_AWHP_SILENT = "mode_awhp_silent" MODE_JET = "mode_jet" diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index dc4d354f..808461e3 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -34,6 +34,7 @@ SUPPORT_JET_COOL = [SUPPORT_RAC_SUBMODE, "@AC_MAIN_WIND_MODE_COOL_JET_W"] SUPPORT_JET_HEAT = [SUPPORT_RAC_SUBMODE, "@AC_MAIN_WIND_MODE_HEAT_JET_W"] SUPPORT_AIRCLEAN = [SUPPORT_RAC_MODE, "@AIRCLEAN"] +SUPPORT_REMOVE_MOISTURE = [SUPPORT_RAC_MODE, "@AUTODRY"] SUPPORT_POWER_SAVE = [SUPPORT_RAC_MODE, "@ENERGYSAVING"] SUPPORT_HOT_WATER = [SUPPORT_PAC_MODE, ["@HOTWATER", "@HOTWATER_ONLY"]] SUPPORT_LIGHT_SWITCH = [SUPPORT_LIGHT, "@RAC_88_DISPLAY_CONTROL"] @@ -72,6 +73,7 @@ STATE_POWER = [STATE_POWER_V1, "airState.energy.onCurrent"] STATE_HUMIDITY = ["SensorHumidity", "airState.humidity.current"] STATE_MODE_AIRCLEAN = ["AirClean", "airState.wMode.airClean"] +STATE_MODE_REMOVE_MOISTURE = ["RemoveMoisture", "airState.miscFuncState.autoDry"] STATE_MODE_POWER_SAVE = ["PowerSave", "airState.powerSave.basic"] STATE_MODE_JET = ["Jet", "airState.wMode.jet"] STATE_LIGHTING_DISPLAY = ["DisplayControl", "airState.lightingState.displayControl"] @@ -104,6 +106,7 @@ CMD_STATE_WDIR_VSWING = [CTRL_WIND_DIRECTION, "Set", STATE_WDIR_VSWING] CMD_STATE_DUCT_ZONES = [CTRL_MISC, "Set", [DUCT_ZONE_V1, "airState.ductZone.control"]] CMD_STATE_MODE_AIRCLEAN = [CTRL_BASIC, "Set", STATE_MODE_AIRCLEAN] +CMD_STATE_MODE_REMOVE_MOISTURE = [CTRL_BASIC, "Set", STATE_MODE_REMOVE_MOISTURE] CMD_STATE_MODE_POWER_SAVE = [CTRL_BASIC, "Set", STATE_MODE_POWER_SAVE] CMD_STATE_MODE_JET = [CTRL_BASIC, "Set", STATE_MODE_JET] CMD_STATE_LIGHTING_DISPLAY = [CTRL_BASIC, "Set", STATE_LIGHTING_DISPLAY] @@ -591,6 +594,11 @@ def is_mode_airclean_supported(self): """Return if AirClean mode is supported.""" return self._is_mode_supported(SUPPORT_AIRCLEAN) + @cached_property + def is_mode_remove_moisture_supported(self): + """Return if RemoveMoisture mode is supported.""" + return self._is_mode_supported(SUPPORT_REMOVE_MOISTURE) + @cached_property def is_mode_power_save_supported(self): """Return if PowerSave mode is supported.""" @@ -757,6 +765,16 @@ async def set_mode_airclean(self, status: bool): mode = self.model_info.enum_value(keys[2], mode_key) await self.set(keys[0], keys[1], key=keys[2], value=mode) + async def set_mode_remove_moisture(self, status: bool): + """Set the RemoveMoisture mode on or off.""" + if not self.is_mode_remove_moisture_supported: + raise ValueError("RemoveMoisture mode not supported") + + keys = self._get_cmd_keys(CMD_STATE_MODE_REMOVE_MOISTURE) + mode_key = MODE_ON if status else MODE_OFF + mode = self.model_info.enum_value(keys[2], mode_key) + await self.set(keys[0], keys[1], key=keys[2], value=mode) + async def set_mode_power_save(self, status: bool): """Set the PowerSave mode on or off.""" if not self.is_mode_power_save_supported: @@ -1205,6 +1223,17 @@ def mode_airclean(self): status = value == MODE_AIRCLEAN_ON return self._update_feature(AirConditionerFeatures.MODE_AIRCLEAN, status, False) + @property + def mode_remove_moisture(self): + """Return RemoveMoisture Mode status.""" + if not self._device.is_mode_remove_moisture_supported: + return None + key = self._get_state_key(STATE_MODE_REMOVE_MOISTURE) + if (value := self.lookup_enum(key, True)) is None: + return None + status = value == MODE_ON + return self._update_feature(AirConditionerFeatures.MODE_REMOVE_MOISTURE, status, False) + @property def mode_power_save(self): """Return PowerSave Mode status.""" @@ -1425,6 +1454,7 @@ def _update_features(self): self.pm25, self.pm1, self.mode_airclean, + self.mode_remove_moisture, self.mode_power_save, self.mode_jet, self.lighting_display, From d757db5e36d022f63fd3f3d67168d90b57651c00 Mon Sep 17 00:00:00 2001 From: Andrei Croitor Date: Fri, 10 May 2024 17:49:16 +0300 Subject: [PATCH 3/3] Fixed Display Light as it was inverted, still only displays the status, doesn't change it --- custom_components/smartthinq_sensors/wideq/devices/ac.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index 808461e3..c07a044f 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -37,8 +37,8 @@ SUPPORT_REMOVE_MOISTURE = [SUPPORT_RAC_MODE, "@AUTODRY"] SUPPORT_POWER_SAVE = [SUPPORT_RAC_MODE, "@ENERGYSAVING"] SUPPORT_HOT_WATER = [SUPPORT_PAC_MODE, ["@HOTWATER", "@HOTWATER_ONLY"]] -SUPPORT_LIGHT_SWITCH = [SUPPORT_LIGHT, "@RAC_88_DISPLAY_CONTROL"] -SUPPORT_LIGHT_INV_SWITCH = [SUPPORT_LIGHT, "@BRIGHTNESS_CONTROL"] +SUPPORT_LIGHT_SWITCH = [SUPPORT_LIGHT, "@BRIGHTNESS_CONTROL"] +#SUPPORT_LIGHT_INV_SWITCH = [SUPPORT_LIGHT, "@RAC_88_DISPLAY_CONTROL"] SUPPORT_PM = [ SUPPORT_AIR_POLUTION, ["@PM1_0_SUPPORT", "@PM2_5_SUPPORT", "@PM10_SUPPORT"], @@ -609,8 +609,8 @@ def supported_ligth_modes(self): """Return light switch modes supported.""" if self._is_mode_supported(SUPPORT_LIGHT_SWITCH): return {MODE_OFF: LIGHT_DISPLAY_OFF, MODE_ON: LIGHT_DISPLAY_ON} - if self._is_mode_supported(SUPPORT_LIGHT_INV_SWITCH): - return {MODE_OFF: LIGHT_DISPLAY_INV_OFF, MODE_ON: LIGHT_DISPLAY_INV_ON} + # if self._is_mode_supported(SUPPORT_LIGHT_INV_SWITCH): + # return {MODE_OFF: LIGHT_DISPLAY_INV_OFF, MODE_ON: LIGHT_DISPLAY_INV_ON} return None @cached_property