From e55b4797675d2333c293e24e88b365a1a5d710f6 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 14:36:59 +0200 Subject: [PATCH 01/13] feat: AC power switch --- custom_components/smartthinq_sensors/switch.py | 8 ++++++++ custom_components/smartthinq_sensors/wideq/const.py | 1 + custom_components/smartthinq_sensors/wideq/devices/ac.py | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 21f4d1e0..f12a0198 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -91,6 +91,14 @@ class ThinQSwitchEntityDescription(SwitchEntityDescription): ), ) AC_SWITCH: tuple[ThinQSwitchEntityDescription, ...] = ( + ThinQSwitchEntityDescription( + key=AirConditionerFeatures.POWER, + name="Power", + icon="mdi:power", + turn_off_fn=lambda x: x.device.power(False), + turn_on_fn=lambda x: x.device.power(True), + value_fn=lambda x: x.is_power_on, + ), ThinQSwitchEntityDescription( key=AirConditionerFeatures.MODE_AIRCLEAN, name="Ionizer", diff --git a/custom_components/smartthinq_sensors/wideq/const.py b/custom_components/smartthinq_sensors/wideq/const.py index 5ff64fd9..e91dc501 100644 --- a/custom_components/smartthinq_sensors/wideq/const.py +++ b/custom_components/smartthinq_sensors/wideq/const.py @@ -44,6 +44,7 @@ class AirConditionerFeatures(StrEnum): PM1 = "pm1" PM10 = "pm10" PM25 = "pm25" + POWER = "power" RESERVATION_SLEEP_TIME = "reservation_sleep_time" ROOM_TEMP = "room_temperature" WATER_IN_TEMP = "water_in_temperature" diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index 8f3ad828..c06e20a5 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -1387,6 +1387,12 @@ def reservation_sleep_time(self): AirConditionerFeatures.RESERVATION_SLEEP_TIME, value, False ) + @property + def power(self): + """Return power status.""" + status = self.is_on + return self._update_feature(AirConditionerFeatures.POWER, status, False) + def _update_features(self): _ = [ self.room_temp, @@ -1404,4 +1410,5 @@ def _update_features(self): self.mode_awhp_silent, self.hot_water_current_temp, self.reservation_sleep_time, + self.power, ] From 9284d03e8384adff75136eadf38b8b074869724c Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 14:58:04 +0200 Subject: [PATCH 02/13] feat: add UVnano to ac --- .../smartthinq_sensors/switch.py | 8 +++++ .../smartthinq_sensors/wideq/const.py | 1 + .../smartthinq_sensors/wideq/devices/ac.py | 33 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index f12a0198..71c77dc9 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -106,6 +106,14 @@ 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.UVNANO, + name="UVnano", + icon="mdi:flash", + turn_off_fn=lambda x: x.device.set_mode_uvnano(False), + turn_on_fn=lambda x: x.device.set_mode_uvnano(True), + available_fn=lambda x: x.is_power_on, + ), 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 e91dc501..bd0217d3 100644 --- a/custom_components/smartthinq_sensors/wideq/const.py +++ b/custom_components/smartthinq_sensors/wideq/const.py @@ -47,6 +47,7 @@ class AirConditionerFeatures(StrEnum): POWER = "power" RESERVATION_SLEEP_TIME = "reservation_sleep_time" ROOM_TEMP = "room_temperature" + UVNANO = "uvnano" WATER_IN_TEMP = "water_in_temperature" WATER_OUT_TEMP = "water_out_temperature" diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index c06e20a5..71b5098f 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -35,6 +35,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_UVNANO = [SUPPORT_RAC_MODE, "@UVNANO"] 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"] @@ -73,6 +74,7 @@ STATE_HUMIDITY = ["SensorHumidity", "airState.humidity.current"] STATE_MODE_AIRCLEAN = ["AirClean", "airState.wMode.airClean"] STATE_MODE_JET = ["Jet", "airState.wMode.jet"] +STATE_MODE_UVNANO = ["UVnano", "airState.wMode.uvnano"] STATE_LIGHTING_DISPLAY = ["DisplayControl", "airState.lightingState.displayControl"] STATE_AIRSENSORMON = ["SensorMon", "airState.quality.sensorMon"] STATE_PM1 = ["SensorPM1", "airState.quality.PM1"] @@ -104,6 +106,7 @@ 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_JET = [CTRL_BASIC, "Set", STATE_MODE_JET] +CMD_STATE_MODE_UVNANO = [CTRL_BASIC, "Set", STATE_MODE_UVNANO] CMD_STATE_LIGHTING_DISPLAY = [CTRL_BASIC, "Set", STATE_LIGHTING_DISPLAY] CMD_RESERVATION_SLEEP_TIME = [CTRL_BASIC, "Set", STATE_RESERVATION_SLEEP_TIME] @@ -152,6 +155,9 @@ MODE_AIRCLEAN_OFF = "@AC_MAIN_AIRCLEAN_OFF_W" MODE_AIRCLEAN_ON = "@AC_MAIN_AIRCLEAN_ON_W" +MODE_UVNANO_OFF = "@AC_MAIN_UVNANO_OFF_W" +MODE_UVNANO_ON = "@AC_MAIN_UVNANO_ON_W" + AWHP_MODE_AIR = "@AIR" AWHP_MODE_WATER = "@WATER" @@ -589,6 +595,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_uvnano_supported(self): + """Return if UVnano mode is supported.""" + return self._is_mode_supported(SUPPORT_UVNANO) + @cached_property def supported_ligth_modes(self): """Return light switch modes supported.""" @@ -750,6 +761,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_uvnano(self, status: bool): + """Set the UVnano mode on or off.""" + if not self.is_mode_uvnano_supported: + raise ValueError("UVnano mode not supported") + + keys = self._get_cmd_keys(CMD_STATE_MODE_UVNANO) + mode_key = MODE_UVNANO_ON if status else MODE_UVNANO_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: @@ -1188,6 +1209,17 @@ def mode_airclean(self): status = value == MODE_AIRCLEAN_ON return self._update_feature(AirConditionerFeatures.MODE_AIRCLEAN, status, False) + @property + def mode_uvnano(self): + """Return UVnano Mode status.""" + if not self._device.is_mode_uvnano_supported: + return None + key = self._get_state_key(STATE_MODE_UVNANO) + if (value := self.lookup_enum(key, True)) is None: + return None + status = value == MODE_UVNANO_ON + return self._update_feature(AirConditionerFeatures.UVNANO, status, False) + @property def mode_jet(self): """Return Jet Mode status.""" @@ -1403,6 +1435,7 @@ def _update_features(self): self.pm25, self.pm1, self.mode_airclean, + self.mode_uvnano, self.mode_jet, self.lighting_display, self.water_in_current_temp, From ea97c3a02f59e7ab5c1eea2e3c3baf1ced93f94f Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 15:15:39 +0200 Subject: [PATCH 03/13] feat: refactor uv_nano naming --- 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 71b5098f..e036931b 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -74,7 +74,7 @@ STATE_HUMIDITY = ["SensorHumidity", "airState.humidity.current"] STATE_MODE_AIRCLEAN = ["AirClean", "airState.wMode.airClean"] STATE_MODE_JET = ["Jet", "airState.wMode.jet"] -STATE_MODE_UVNANO = ["UVnano", "airState.wMode.uvnano"] +STATE_UV_NANO = ["UVnano", "airState.wMode.uvnano"] STATE_LIGHTING_DISPLAY = ["DisplayControl", "airState.lightingState.displayControl"] STATE_AIRSENSORMON = ["SensorMon", "airState.quality.sensorMon"] STATE_PM1 = ["SensorPM1", "airState.quality.PM1"] @@ -106,7 +106,7 @@ 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_JET = [CTRL_BASIC, "Set", STATE_MODE_JET] -CMD_STATE_MODE_UVNANO = [CTRL_BASIC, "Set", STATE_MODE_UVNANO] +CMD_STATE_UV_NANO = [CTRL_BASIC, "Set", STATE_UV_NANO] CMD_STATE_LIGHTING_DISPLAY = [CTRL_BASIC, "Set", STATE_LIGHTING_DISPLAY] CMD_RESERVATION_SLEEP_TIME = [CTRL_BASIC, "Set", STATE_RESERVATION_SLEEP_TIME] @@ -766,7 +766,7 @@ async def set_mode_uvnano(self, status: bool): if not self.is_mode_uvnano_supported: raise ValueError("UVnano mode not supported") - keys = self._get_cmd_keys(CMD_STATE_MODE_UVNANO) + keys = self._get_cmd_keys(CMD_STATE_UV_NANO) mode_key = MODE_UVNANO_ON if status else MODE_UVNANO_OFF mode = self.model_info.enum_value(keys[2], mode_key) await self.set(keys[0], keys[1], key=keys[2], value=mode) @@ -1214,7 +1214,7 @@ def mode_uvnano(self): """Return UVnano Mode status.""" if not self._device.is_mode_uvnano_supported: return None - key = self._get_state_key(STATE_MODE_UVNANO) + key = self._get_state_key(STATE_UV_NANO) if (value := self.lookup_enum(key, True)) is None: return None status = value == MODE_UVNANO_ON From acc146ef75a9d3bfe29548c5cf1c430da90814bd Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 15:21:39 +0200 Subject: [PATCH 04/13] feat: refactor uv_nano --- custom_components/smartthinq_sensors/switch.py | 4 ++-- custom_components/smartthinq_sensors/wideq/devices/ac.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 71c77dc9..238d3898 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -110,8 +110,8 @@ class ThinQSwitchEntityDescription(SwitchEntityDescription): key=AirConditionerFeatures.UVNANO, name="UVnano", icon="mdi:flash", - turn_off_fn=lambda x: x.device.set_mode_uvnano(False), - turn_on_fn=lambda x: x.device.set_mode_uvnano(True), + turn_off_fn=lambda x: x.device.set_uv_nano(False), + turn_on_fn=lambda x: x.device.set_uv_nano(True), available_fn=lambda x: x.is_power_on, ), ThinQSwitchEntityDescription( diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index e036931b..d9f77dbd 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -155,8 +155,8 @@ MODE_AIRCLEAN_OFF = "@AC_MAIN_AIRCLEAN_OFF_W" MODE_AIRCLEAN_ON = "@AC_MAIN_AIRCLEAN_ON_W" -MODE_UVNANO_OFF = "@AC_MAIN_UVNANO_OFF_W" -MODE_UVNANO_ON = "@AC_MAIN_UVNANO_ON_W" +UV_NANO_OFF = "0" +UV_NANO_ON = "1" AWHP_MODE_AIR = "@AIR" AWHP_MODE_WATER = "@WATER" From 0efb8a0ef859600228bf8d0ac06e2303a9044484 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 15:27:12 +0200 Subject: [PATCH 05/13] feat: update uvstate key --- .../smartthinq_sensors/wideq/devices/ac.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index d9f77dbd..631b59b5 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -35,7 +35,12 @@ 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_UVNANO = [SUPPORT_RAC_MODE, "@UVNANO"] +# Try different possible support keys for UVnano +# SUPPORT_UVNANO = [SUPPORT_RAC_MODE, "@UVNANO"] +# Alternative support keys to try if the above doesn't work: +SUPPORT_UVNANO = [SUPPORT_RAC_MODE, "@UV_NANO"] +# SUPPORT_UVNANO = [SUPPORT_RAC_SUBMODE, "@UV_NANO"] +# SUPPORT_UVNANO = ["SupportUVnano", "support.uvnano"] 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"] @@ -74,7 +79,7 @@ STATE_HUMIDITY = ["SensorHumidity", "airState.humidity.current"] STATE_MODE_AIRCLEAN = ["AirClean", "airState.wMode.airClean"] STATE_MODE_JET = ["Jet", "airState.wMode.jet"] -STATE_UV_NANO = ["UVnano", "airState.wMode.uvnano"] +STATE_UV_NANO = ["UVNano", "airState.miscFuncState.Uvnano"] STATE_LIGHTING_DISPLAY = ["DisplayControl", "airState.lightingState.displayControl"] STATE_AIRSENSORMON = ["SensorMon", "airState.quality.sensorMon"] STATE_PM1 = ["SensorPM1", "airState.quality.PM1"] @@ -598,7 +603,9 @@ def is_mode_airclean_supported(self): @cached_property def is_mode_uvnano_supported(self): """Return if UVnano mode is supported.""" - return self._is_mode_supported(SUPPORT_UVNANO) + supported = self._is_mode_supported(SUPPORT_UVNANO) + _LOGGER.debug("UVnano support check: %s (support key: %s)", supported, SUPPORT_UVNANO) + return supported @cached_property def supported_ligth_modes(self): @@ -767,7 +774,7 @@ async def set_mode_uvnano(self, status: bool): raise ValueError("UVnano mode not supported") keys = self._get_cmd_keys(CMD_STATE_UV_NANO) - mode_key = MODE_UVNANO_ON if status else MODE_UVNANO_OFF + mode_key = UV_NANO_ON if status else UV_NANO_OFF mode = self.model_info.enum_value(keys[2], mode_key) await self.set(keys[0], keys[1], key=keys[2], value=mode) @@ -1217,7 +1224,7 @@ def mode_uvnano(self): key = self._get_state_key(STATE_UV_NANO) if (value := self.lookup_enum(key, True)) is None: return None - status = value == MODE_UVNANO_ON + status = value == UV_NANO_ON return self._update_feature(AirConditionerFeatures.UVNANO, status, False) @property From a625866f4b99fd2064400e2ec27eab7bdd2d7c26 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 15:33:09 +0200 Subject: [PATCH 06/13] feat: disable check status --- 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 631b59b5..1ce5fae1 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -770,8 +770,8 @@ async def set_mode_airclean(self, status: bool): async def set_mode_uvnano(self, status: bool): """Set the UVnano mode on or off.""" - if not self.is_mode_uvnano_supported: - raise ValueError("UVnano mode not supported") + # if not self.is_mode_uvnano_supported: + # raise ValueError("UVnano mode not supported") keys = self._get_cmd_keys(CMD_STATE_UV_NANO) mode_key = UV_NANO_ON if status else UV_NANO_OFF @@ -1219,8 +1219,8 @@ def mode_airclean(self): @property def mode_uvnano(self): """Return UVnano Mode status.""" - if not self._device.is_mode_uvnano_supported: - return None + # if not self._device.is_mode_uvnano_supported: + # return None key = self._get_state_key(STATE_UV_NANO) if (value := self.lookup_enum(key, True)) is None: return None From 02f7fa6ff414d29732b8354902b659b58879d598 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 16:43:46 +0200 Subject: [PATCH 07/13] feat: set uvnano mode --- .../smartthinq_sensors/wideq/devices/ac.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index 1ce5fae1..0e741eab 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -601,7 +601,7 @@ def is_mode_airclean_supported(self): return self._is_mode_supported(SUPPORT_AIRCLEAN) @cached_property - def is_mode_uvnano_supported(self): + def is_uv_nano_supported(self): """Return if UVnano mode is supported.""" supported = self._is_mode_supported(SUPPORT_UVNANO) _LOGGER.debug("UVnano support check: %s (support key: %s)", supported, SUPPORT_UVNANO) @@ -768,9 +768,9 @@ 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_uvnano(self, status: bool): + async def set_uv_nano(self, status: bool): """Set the UVnano mode on or off.""" - # if not self.is_mode_uvnano_supported: + # if not self.is_uv_nano_supported: # raise ValueError("UVnano mode not supported") keys = self._get_cmd_keys(CMD_STATE_UV_NANO) @@ -1217,9 +1217,9 @@ def mode_airclean(self): return self._update_feature(AirConditionerFeatures.MODE_AIRCLEAN, status, False) @property - def mode_uvnano(self): + def uv_nano(self): """Return UVnano Mode status.""" - # if not self._device.is_mode_uvnano_supported: + # if not self._device.is_uv_nano_supported: # return None key = self._get_state_key(STATE_UV_NANO) if (value := self.lookup_enum(key, True)) is None: @@ -1442,7 +1442,7 @@ def _update_features(self): self.pm25, self.pm1, self.mode_airclean, - self.mode_uvnano, + self.uv_nano, self.mode_jet, self.lighting_display, self.water_in_current_temp, From 6efe0b343c687db0fe47b6e862438ea37d57e6bb Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 17:01:56 +0200 Subject: [PATCH 08/13] fix: set uv cmd debug --- .../smartthinq_sensors/wideq/devices/ac.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index 0e741eab..fbb868ae 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -775,7 +775,18 @@ async def set_uv_nano(self, status: bool): keys = self._get_cmd_keys(CMD_STATE_UV_NANO) mode_key = UV_NANO_ON if status else UV_NANO_OFF - mode = self.model_info.enum_value(keys[2], mode_key) + + # Try direct value first (since we're using "0" and "1") + mode = mode_key + + # Fallback to enum lookup if needed + if mode == UV_NANO_ON or mode == UV_NANO_OFF: + enum_mode = self.model_info.enum_value(keys[2], mode_key) + if enum_mode is not None: + mode = enum_mode + + _LOGGER.debug("UVnano set command - keys: %s, mode_key: %s, final_mode: %s", keys, mode_key, mode) + await self.set(keys[0], keys[1], key=keys[2], value=mode) async def set_mode_jet(self, status: bool): @@ -1222,9 +1233,16 @@ def uv_nano(self): # if not self._device.is_uv_nano_supported: # return None key = self._get_state_key(STATE_UV_NANO) - if (value := self.lookup_enum(key, True)) is None: + value = self.lookup_enum(key, True) + + _LOGGER.debug("UVnano status - key: %s, raw_value: %s", key, value) + + if value is None: return None status = value == UV_NANO_ON + + _LOGGER.debug("UVnano status - processed: %s (raw: %s, expected_on: %s)", status, value, UV_NANO_ON) + return self._update_feature(AirConditionerFeatures.UVNANO, status, False) @property From c1eec8280d39afd39fff42848765456bf98994c2 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 17:07:42 +0200 Subject: [PATCH 09/13] fix: debug for on and off values --- .../smartthinq_sensors/wideq/devices/ac.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index fbb868ae..565be42d 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -1233,13 +1233,25 @@ def uv_nano(self): # if not self._device.is_uv_nano_supported: # return None key = self._get_state_key(STATE_UV_NANO) + + # Try both enum lookup and direct data access value = self.lookup_enum(key, True) + if value is None: + # Fallback to direct data access + value = self._data.get(key) - _LOGGER.debug("UVnano status - key: %s, raw_value: %s", key, value) + _LOGGER.debug("UVnano status - key: %s, raw_value: %s, data_keys: %s", key, value, list(self._data.keys()) if hasattr(self, '_data') else 'No data') if value is None: return None - status = value == UV_NANO_ON + + # Handle different possible value formats + if isinstance(value, str): + status = value == UV_NANO_ON or value == "1" or value.lower() == "on" + elif isinstance(value, (int, float)): + status = value == 1 + else: + status = bool(value) _LOGGER.debug("UVnano status - processed: %s (raw: %s, expected_on: %s)", status, value, UV_NANO_ON) From 768947fc012b0375da4bdf7b0b84953d76f1be1a Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Wed, 20 Aug 2025 17:11:07 +0200 Subject: [PATCH 10/13] fix: on off values for uvnano --- .../smartthinq_sensors/wideq/devices/ac.py | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index 565be42d..d440606e 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -160,8 +160,8 @@ MODE_AIRCLEAN_OFF = "@AC_MAIN_AIRCLEAN_OFF_W" MODE_AIRCLEAN_ON = "@AC_MAIN_AIRCLEAN_ON_W" -UV_NANO_OFF = "0" -UV_NANO_ON = "1" +UV_NANO_OFF = "@OFF" +UV_NANO_ON = "@ON" AWHP_MODE_AIR = "@AIR" AWHP_MODE_WATER = "@WATER" @@ -775,17 +775,13 @@ async def set_uv_nano(self, status: bool): keys = self._get_cmd_keys(CMD_STATE_UV_NANO) mode_key = UV_NANO_ON if status else UV_NANO_OFF - - # Try direct value first (since we're using "0" and "1") - mode = mode_key - - # Fallback to enum lookup if needed - if mode == UV_NANO_ON or mode == UV_NANO_OFF: - enum_mode = self.model_info.enum_value(keys[2], mode_key) - if enum_mode is not None: - mode = enum_mode + mode = self.model_info.enum_value(keys[2], mode_key) _LOGGER.debug("UVnano set command - keys: %s, mode_key: %s, final_mode: %s", keys, mode_key, mode) + + if mode is None: + _LOGGER.error("UVnano mode value not found in model info for key: %s", mode_key) + raise ValueError(f"UVnano mode value not found for key: {mode_key}") await self.set(keys[0], keys[1], key=keys[2], value=mode) @@ -1233,25 +1229,14 @@ def uv_nano(self): # if not self._device.is_uv_nano_supported: # return None key = self._get_state_key(STATE_UV_NANO) - - # Try both enum lookup and direct data access value = self.lookup_enum(key, True) - if value is None: - # Fallback to direct data access - value = self._data.get(key) - _LOGGER.debug("UVnano status - key: %s, raw_value: %s, data_keys: %s", key, value, list(self._data.keys()) if hasattr(self, '_data') else 'No data') + _LOGGER.debug("UVnano status - key: %s, raw_value: %s", key, value) if value is None: return None - # Handle different possible value formats - if isinstance(value, str): - status = value == UV_NANO_ON or value == "1" or value.lower() == "on" - elif isinstance(value, (int, float)): - status = value == 1 - else: - status = bool(value) + status = value == UV_NANO_ON _LOGGER.debug("UVnano status - processed: %s (raw: %s, expected_on: %s)", status, value, UV_NANO_ON) From ff3d45bc5f54133c13cd340788ee2ea6c61efe8a Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Thu, 21 Aug 2025 09:15:59 +0200 Subject: [PATCH 11/13] feat: try supppported nano --- 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 d440606e..bbab5676 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -770,8 +770,8 @@ async def set_mode_airclean(self, status: bool): async def set_uv_nano(self, status: bool): """Set the UVnano mode on or off.""" - # if not self.is_uv_nano_supported: - # raise ValueError("UVnano mode not supported") + if not self.is_uv_nano_supported: + raise ValueError("UVnano mode not supported") keys = self._get_cmd_keys(CMD_STATE_UV_NANO) mode_key = UV_NANO_ON if status else UV_NANO_OFF @@ -1226,8 +1226,8 @@ def mode_airclean(self): @property def uv_nano(self): """Return UVnano Mode status.""" - # if not self._device.is_uv_nano_supported: - # return None + if not self._device.is_uv_nano_supported: + return None key = self._get_state_key(STATE_UV_NANO) value = self.lookup_enum(key, True) From 83d97b95b646161f316a6822b0beb48cb0dd8e74 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Thu, 21 Aug 2025 09:29:14 +0200 Subject: [PATCH 12/13] feat: try supppported nano misc --- custom_components/smartthinq_sensors/switch.py | 5 +++++ .../smartthinq_sensors/wideq/devices/ac.py | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 238d3898..6548eb17 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -177,6 +177,11 @@ def _switch_exist( if feature in lge_device.available_features: return True + # Special case for UVnano - check if device supports it directly + if feature == AirConditionerFeatures.UVNANO: + if hasattr(lge_device.device, 'is_uv_nano_supported'): + return lge_device.device.is_uv_nano_supported + return False diff --git a/custom_components/smartthinq_sensors/wideq/devices/ac.py b/custom_components/smartthinq_sensors/wideq/devices/ac.py index bbab5676..a4ef7fd3 100644 --- a/custom_components/smartthinq_sensors/wideq/devices/ac.py +++ b/custom_components/smartthinq_sensors/wideq/devices/ac.py @@ -37,9 +37,10 @@ SUPPORT_AIRCLEAN = [SUPPORT_RAC_MODE, "@AIRCLEAN"] # Try different possible support keys for UVnano # SUPPORT_UVNANO = [SUPPORT_RAC_MODE, "@UVNANO"] -# Alternative support keys to try if the above doesn't work: -SUPPORT_UVNANO = [SUPPORT_RAC_MODE, "@UV_NANO"] +# SUPPORT_UVNANO = [SUPPORT_RAC_MODE, "@UV_NANO"] # SUPPORT_UVNANO = [SUPPORT_RAC_SUBMODE, "@UV_NANO"] +# Alternative based on miscFuncState location: +SUPPORT_UVNANO = ["SupportMiscFuncState", "support.miscFuncState"] # SUPPORT_UVNANO = ["SupportUVnano", "support.uvnano"] SUPPORT_HOT_WATER = [SUPPORT_PAC_MODE, ["@HOTWATER", "@HOTWATER_ONLY"]] SUPPORT_LIGHT_SWITCH = [SUPPORT_LIGHT, "@RAC_88_DISPLAY_CONTROL"] @@ -603,8 +604,18 @@ def is_mode_airclean_supported(self): @cached_property def is_uv_nano_supported(self): """Return if UVnano mode is supported.""" + # First try the traditional support check supported = self._is_mode_supported(SUPPORT_UVNANO) - _LOGGER.debug("UVnano support check: %s (support key: %s)", supported, SUPPORT_UVNANO) + _LOGGER.debug("UVnano support check via model: %s (support key: %s)", supported, SUPPORT_UVNANO) + + # If traditional check fails, check if the data is present in the device status + if not supported and self._status: + key = self._get_state_key(STATE_UV_NANO) + data_present = key in self._status._data if hasattr(self._status, '_data') else False + _LOGGER.debug("UVnano support check via data presence: %s (key: %s)", data_present, key) + supported = data_present + + _LOGGER.debug("UVnano final support decision: %s", supported) return supported @cached_property From eec951f0032b40a38bb2a824a0b687c4dd7f8d68 Mon Sep 17 00:00:00 2001 From: Jonas Vercammen Date: Thu, 21 Aug 2025 10:16:08 +0200 Subject: [PATCH 13/13] fix: remove restriction uvnano dependency power state device --- custom_components/smartthinq_sensors/switch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/smartthinq_sensors/switch.py b/custom_components/smartthinq_sensors/switch.py index 6548eb17..98d8e3a3 100644 --- a/custom_components/smartthinq_sensors/switch.py +++ b/custom_components/smartthinq_sensors/switch.py @@ -112,7 +112,6 @@ class ThinQSwitchEntityDescription(SwitchEntityDescription): icon="mdi:flash", turn_off_fn=lambda x: x.device.set_uv_nano(False), turn_on_fn=lambda x: x.device.set_uv_nano(True), - available_fn=lambda x: x.is_power_on, ), ThinQSwitchEntityDescription( key=AirConditionerFeatures.MODE_JET,