Fix ValueError for non-numeric value in LG ThinQ (#166300)

Co-authored-by: YunseonPark-LGE <yunseon.park@lge.com>
This commit is contained in:
LG-ThinQ-Integration
2026-05-14 16:37:33 +02:00
committed by GitHub
co-authored by YunseonPark-LGE
parent 0cca80e57d
commit 4696e428cf
9 changed files with 414 additions and 6 deletions
+64 -5
View File
@@ -518,10 +518,6 @@ DEVICE_TYPE_SENSOR_MAP: dict[DeviceType, tuple[SensorEntityDescription, ...]] =
),
DeviceType.KIMCHI_REFRIGERATOR: (
REFRIGERATION_SENSOR_DESC[ThinQProperty.FRESH_AIR_FILTER],
SensorEntityDescription(
key=ThinQProperty.TARGET_TEMPERATURE,
translation_key=ThinQProperty.TARGET_TEMPERATURE,
),
),
DeviceType.MICROWAVE_OVEN: (RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],),
DeviceType.OVEN: (
@@ -592,6 +588,17 @@ DEVICE_TYPE_SENSOR_MAP: dict[DeviceType, tuple[SensorEntityDescription, ...]] =
}
ENUM_TEMPERATURE_SENSOR_MAP: dict[DeviceType, tuple[SensorEntityDescription, ...]] = {
DeviceType.KIMCHI_REFRIGERATOR: (
SensorEntityDescription(
key=ThinQProperty.TARGET_TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
translation_key=ThinQProperty.TARGET_TEMPERATURE,
),
),
}
@dataclass(frozen=True, kw_only=True)
class ThinQEnergySensorEntityDescription(SensorEntityDescription):
"""Describes ThinQ energy sensor entity."""
@@ -639,7 +646,9 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up an entry for sensor platform."""
entities: list[ThinQSensorEntity | ThinQEnergySensorEntity] = []
entities: list[
ThinQSensorEntity | ThinQEnergySensorEntity | ThinQEnumTempSensorEntity
] = []
for coordinator in entry.runtime_data.coordinators.values():
if (
descriptions := DEVICE_TYPE_SENSOR_MAP.get(
@@ -661,6 +670,21 @@ async def async_setup_entry(
),
)
)
if (
descriptions := ENUM_TEMPERATURE_SENSOR_MAP.get(
coordinator.api.device.device_type
)
) is not None:
for description in descriptions:
entities.extend(
ThinQEnumTempSensorEntity(coordinator, description, property_id)
for property_id in coordinator.api.get_active_idx(
description.key,
ActiveMode.READ_ONLY,
)
)
for energy_description in ENERGY_USAGE_SENSORS:
entities.extend(
ThinQEnergySensorEntity(
@@ -860,3 +884,38 @@ class ThinQEnergySensorEntity(ThinQEntity, SensorEntity):
self.async_update,
next_update,
)
class ThinQEnumTempSensorEntity(ThinQEntity, SensorEntity):
"""Represent a thinq sensor platform."""
def __init__(
self,
coordinator: DeviceDataUpdateCoordinator,
entity_description: SensorEntityDescription,
property_id: str,
) -> None:
"""Initialize a sensor entity."""
super().__init__(coordinator, entity_description, property_id)
if self.data.options:
# some kimchi refrigerator's target temperature have data in the form of string with enum options.
# Set options to display the correct value in the UI.
self._attr_options = self.data.options
self._attr_device_class = SensorDeviceClass.ENUM
self._attr_native_unit_of_measurement = None
def _update_status(self) -> None:
"""Update status itself."""
super()._update_status()
self._attr_native_value = self.data.value
_LOGGER.debug(
"[%s:%s] update status: %s -> %s, options:%s, unit:%s",
self.coordinator.device_name,
self.property_id,
self.data.value,
self.native_value,
self.options,
self.native_unit_of_measurement,
)
+1
View File
@@ -117,6 +117,7 @@ def mock_thinq_mqtt_client() -> Generator[None]:
"air_conditioner",
"washer",
"dehumidifier",
"kimchi_refrigerator",
]
)
def device_fixture(request: pytest.FixtureRequest) -> Generator[str]:
@@ -0,0 +1,9 @@
{
"deviceId": "MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F",
"deviceInfo": {
"deviceType": "DEVICE_KIMCHI_REFRIGERATOR",
"modelName": "2REB1KRS11__H",
"alias": "Test kimchi refrigerator",
"reportable": true
}
}
@@ -0,0 +1,6 @@
{
"resultCode": "0000",
"result": {
"property": ["energyUsage"]
}
}
@@ -0,0 +1,29 @@
{
"notification": {
"push": ["DOOR_IS_OPEN"]
},
"property": {
"temperature": [
{
"locationName": "TOP",
"targetTemperature": {
"mode": ["r"],
"type": "enum",
"value": {
"r": ["TEMPERATURE_NUMBER"]
}
}
},
{
"locationName": "MIDDLE",
"targetTemperature": {
"mode": ["r"],
"type": "enum",
"value": {
"r": ["KIMCHI", "MEAT_FISH", "VEGETABLE_FRUIT"]
}
}
}
]
}
}
@@ -0,0 +1,12 @@
{
"temperature": [
{
"locationName": "TOP",
"targetTemperature": 6
},
{
"locationName": "MIDDLE",
"targetTemperature": "KIMCHI"
}
]
}
@@ -605,3 +605,290 @@
'state': '2024-10-10T13:14:00+00:00',
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_last_month-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_last_month',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Energy last month',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Energy last month',
'platform': 'lg_thinq',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_usage_last_month',
'unique_id': 'MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F_energyUsage_last_month',
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_last_month-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Test kimchi refrigerator Energy last month',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_last_month',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_this_month-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_this_month',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Energy this month',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Energy this month',
'platform': 'lg_thinq',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_usage_this_month',
'unique_id': 'MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F_energyUsage_this_month',
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_this_month-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Test kimchi refrigerator Energy this month',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_this_month',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_yesterday-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_yesterday',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Energy yesterday',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Energy yesterday',
'platform': 'lg_thinq',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_usage_yesterday',
'unique_id': 'MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F_energyUsage_yesterday',
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_energy_yesterday-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Test kimchi refrigerator Energy yesterday',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.WATT_HOUR: 'Wh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_kimchi_refrigerator_energy_yesterday',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_middle_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'options': list([
'kimchi',
'meat_fish',
'vegetable_fruit',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_kimchi_refrigerator_middle_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'middle temperature',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'middle temperature',
'platform': 'lg_thinq',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'target_temperature_for_location',
'unique_id': 'MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F_middle_target_temperature',
'unit_of_measurement': None,
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_middle_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Test kimchi refrigerator middle temperature',
'options': list([
'kimchi',
'meat_fish',
'vegetable_fruit',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.test_kimchi_refrigerator_middle_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'kimchi',
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_top_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_kimchi_refrigerator_top_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'top temperature',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'top temperature',
'platform': 'lg_thinq',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'target_temperature_for_location',
'unique_id': 'MW2-FD94EF23-EF86-4D65-92AB-5399A90C228F_top_target_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensor_entities[kimchi_refrigerator][sensor.test_kimchi_refrigerator_top_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Test kimchi refrigerator top temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_kimchi_refrigerator_top_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '6',
})
# ---
+1 -1
View File
@@ -23,7 +23,7 @@ from tests.common import (
)
@pytest.mark.parametrize("device_fixture", ["air_conditioner"])
@pytest.mark.parametrize("device_fixture", ["air_conditioner", "kimchi_refrigerator"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.freeze_time(datetime(2024, 10, 10, tzinfo=UTC))
async def test_sensor_entities(
+5
View File
@@ -2,6 +2,7 @@
from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform
@@ -13,6 +14,10 @@ from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize(
"device_fixture", ["air_conditioner", "dehumidifier", "washer"]
)
async def test_switch_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,