HEX
Server: Apache/2.4.63 (Unix)
System: Linux Synopilou92 4.4.302+ #72806 SMP Mon Jul 21 23:16:00 CST 2025 x86_64
User: pilou92 (1026)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /volume1/docker/homeassistant2025/custom_components/smartthinq_sensors/sensor.py
"""Support for ThinQ device sensors."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import time
import logging
from typing import Any, Callable

import voluptuous as vol

from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    SensorEntityDescription,
    SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
    CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    PERCENTAGE,
    STATE_UNAVAILABLE,
    EntityCategory,
    UnitOfPower,
    UnitOfTime,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback, current_platform
from homeassistant.helpers.typing import UNDEFINED
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import LGEDevice
from .const import (
    ATTR_CURRENT_COURSE,
    ATTR_FREEZER_TEMP,
    ATTR_FRIDGE_TEMP,
    ATTR_INITIAL_TIME,
    ATTR_OVEN_LOWER_TARGET_TEMP,
    ATTR_OVEN_UPPER_TARGET_TEMP,
    ATTR_REMAIN_TIME,
    ATTR_RESERVE_TIME,
    DEFAULT_ICON,
    DEFAULT_SENSOR,
    DOMAIN,
    LGE_DEVICES,
    LGE_DISCOVERY_NEW,
)
from .device_helpers import (
    DEVICE_ICONS,
    WASH_DEVICE_TYPES,
    LGEBaseDevice,
    get_entity_name,
    get_wrapper_device,
)
from .wideq import (
    SET_TIME_DEVICE_TYPES,
    WM_DEVICE_TYPES,
    AirConditionerFeatures,
    AirPurifierFeatures,
    DehumidifierFeatures,
    DeviceType,
    MicroWaveFeatures,
    RangeFeatures,
    RefrigeratorFeatures,
    WashDeviceFeatures,
    WaterHeaterFeatures,
)

# service definition
SERVICE_REMOTE_START = "remote_start"
SERVICE_WAKE_UP = "wake_up"
SERVICE_SET_TIME = "set_time"

# supported features
# this is used to limit the device's entities
# used to call the specific service
SUPPORT_WM_SERVICES = 1
SUPPORT_SET_TIME = 2

_LOGGER = logging.getLogger(__name__)


@dataclass
class ThinQSensorEntityDescription(SensorEntityDescription):
    """A class that describes ThinQ sensor entities."""

    unit_fn: Callable[[Any], str] | None = None
    value_fn: Callable[[Any], float | str] | None = None
    feature_attributes: dict[str, str] | None = None


WASH_DEV_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DEFAULT_SENSOR,
        icon=DEFAULT_ICON,
        value_fn=lambda x: x.power_state,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_CURRENT_COURSE,
        name="Current course",
        icon="mdi:pin-outline",
        value_fn=lambda x: x.current_course,
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.RUN_STATE,
        name="Run state",
        icon=DEFAULT_ICON,
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.PROCESS_STATE,
        name="Process state",
        icon=DEFAULT_ICON,
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.SPINSPEED,
        name="Spin speed",
        icon="mdi:rotate-3d",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.WATERTEMP,
        name="Water temp",
        icon="mdi:thermometer-lines",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.RINSEMODE,
        name="Rinse mode",
        icon="mdi:waves",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.TEMPCONTROL,
        name="Temp control",
        icon="mdi:thermometer-lines",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.DRYLEVEL,
        name="Dry level",
        icon="mdi:tumble-dryer",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.ERROR_MSG,
        name="Error message",
        icon="mdi:alert-circle-outline",
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.PRE_STATE,
        name="Pre state",
        icon=DEFAULT_ICON,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.TUBCLEAN_COUNT,
        name="Tub clean counter",
        icon=DEFAULT_ICON,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=WashDeviceFeatures.HALFLOAD,
        name="Half load",
        icon="mdi:circle-half-full",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_INITIAL_TIME,
        name="Initial time",
        icon="mdi:clock-outline",
        value_fn=lambda x: x.initial_time,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_REMAIN_TIME,
        name="Remaining time",
        icon="mdi:clock-outline",
        value_fn=lambda x: x.remain_time,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_RESERVE_TIME,
        name="Countdown time",
        icon="mdi:clock-outline",
        value_fn=lambda x: x.reserve_time,
        entity_registry_enabled_default=False,
    ),
)
REFRIGERATOR_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DEFAULT_SENSOR,
        icon=DEFAULT_ICON,
        value_fn=lambda x: x.power_state,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_FRIDGE_TEMP,
        name="Fridge temp",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        value_fn=lambda x: x.temp_fridge,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_FREEZER_TEMP,
        name="Freezer temp",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        value_fn=lambda x: x.temp_freezer,
    ),
    ThinQSensorEntityDescription(
        key=RefrigeratorFeatures.FRESHAIRFILTER_REMAIN_PERC,
        name="Fresh air filter remaining",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
    ),
    ThinQSensorEntityDescription(
        key=RefrigeratorFeatures.WATERFILTER_REMAIN_PERC,
        name="Water filter remaining",
        icon="mdi:waves",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
    ),
)
AC_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.ROOM_TEMP,
        name="Room temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.HOT_WATER_TEMP,
        name="Hot water temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.WATER_IN_TEMP,
        name="In water temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.WATER_OUT_TEMP,
        name="Out water temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.ENERGY_CURRENT,
        name="Energy current",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.POWER,
        native_unit_of_measurement=UnitOfPower.WATT,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.HUMIDITY,
        name="Humidity",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.HUMIDITY,
        native_unit_of_measurement=PERCENTAGE,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.PM1,
        name="PM1",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM1,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.PM10,
        name="PM10",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM10,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.PM25,
        name="PM2.5",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM25,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.FILTER_MAIN_LIFE,
        name="Filter Remaining Life",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirConditionerFeatures.FILTER_MAIN_USE,
            "max_time": AirConditionerFeatures.FILTER_MAIN_MAX,
        },
    ),
    ThinQSensorEntityDescription(
        key=AirConditionerFeatures.RESERVATION_SLEEP_TIME,
        name="Sleep time",
        icon="mdi:weather-night",
        state_class=SensorDeviceClass.DURATION,
        native_unit_of_measurement=UnitOfTime.MINUTES,
    ),
)
RANGE_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DEFAULT_SENSOR,
        icon=DEFAULT_ICON,
        value_fn=lambda x: x.power_state,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.COOKTOP_LEFT_FRONT_STATE,
        name="Cooktop left front state",
        icon="mdi:arrow-left-bold-box-outline",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.COOKTOP_LEFT_REAR_STATE,
        name="Cooktop left rear state",
        icon="mdi:arrow-left-bold-box",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.COOKTOP_CENTER_STATE,
        name="Cooktop center state",
        icon="mdi:minus-box-outline",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.COOKTOP_RIGHT_FRONT_STATE,
        name="Cooktop right front state",
        icon="mdi:arrow-right-bold-box-outline",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.COOKTOP_RIGHT_REAR_STATE,
        name="Cooktop right rear state",
        icon="mdi:arrow-right-bold-box",
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_LOWER_STATE,
        name="Oven lower state",
        icon="mdi:inbox-arrow-down",
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_LOWER_MODE,
        name="Oven lower mode",
        icon="mdi:inbox-arrow-down",
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_UPPER_STATE,
        name="Oven upper state",
        icon="mdi:inbox-arrow-up",
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_UPPER_MODE,
        name="Oven upper mode",
        icon="mdi:inbox-arrow-up",
    ),
    ThinQSensorEntityDescription(
        key=ATTR_OVEN_LOWER_TARGET_TEMP,
        name="Oven lower target temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.oven_temp_unit,
        value_fn=lambda x: x.oven_lower_target_temp,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_LOWER_CURRENT_TEMP,
        name="Oven lower current temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.oven_temp_unit,
    ),
    ThinQSensorEntityDescription(
        key=ATTR_OVEN_UPPER_TARGET_TEMP,
        name="Oven upper target temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.oven_temp_unit,
        value_fn=lambda x: x.oven_upper_target_temp,
    ),
    ThinQSensorEntityDescription(
        key=RangeFeatures.OVEN_UPPER_CURRENT_TEMP,
        name="Oven upper current temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.oven_temp_unit,
    ),
)
AIR_PURIFIER_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.HUMIDITY,
        name="Current Humidity",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.HUMIDITY,
        native_unit_of_measurement=PERCENTAGE,
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.PM1,
        name="PM1",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM1,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.PM10,
        name="PM10",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM10,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.PM25,
        name="PM2.5",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.PM25,
        native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.FILTER_MAIN_LIFE,
        name="Filter Remaining Life (Main)",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirPurifierFeatures.FILTER_MAIN_USE,
            "max_time": AirPurifierFeatures.FILTER_MAIN_MAX,
        },
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.FILTER_BOTTOM_LIFE,
        name="Filter Remaining Life (Bottom)",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirPurifierFeatures.FILTER_BOTTOM_USE,
            "max_time": AirPurifierFeatures.FILTER_BOTTOM_MAX,
        },
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.FILTER_DUST_LIFE,
        name="Filter Remaining Life (Dust)",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirPurifierFeatures.FILTER_DUST_USE,
            "max_time": AirPurifierFeatures.FILTER_DUST_MAX,
        },
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.FILTER_MID_LIFE,
        name="Filter Remaining Life (Middle)",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirPurifierFeatures.FILTER_MID_USE,
            "max_time": AirPurifierFeatures.FILTER_MID_MAX,
        },
    ),
    ThinQSensorEntityDescription(
        key=AirPurifierFeatures.FILTER_TOP_LIFE,
        name="Filter Remaining Life (Top)",
        icon="mdi:air-filter",
        state_class=SensorStateClass.MEASUREMENT,
        native_unit_of_measurement=PERCENTAGE,
        feature_attributes={
            "use_time": AirPurifierFeatures.FILTER_TOP_USE,
            "max_time": AirPurifierFeatures.FILTER_TOP_MAX,
        },
    ),
)
DEHUMIDIFIER_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DehumidifierFeatures.HUMIDITY,
        name="Current Humidity",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.HUMIDITY,
        native_unit_of_measurement=PERCENTAGE,
    ),
    ThinQSensorEntityDescription(
        key=DehumidifierFeatures.TARGET_HUMIDITY,
        name="Target Humidity",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.HUMIDITY,
        native_unit_of_measurement=PERCENTAGE,
        entity_registry_enabled_default=False,
    ),
)
WATER_HEATER_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=WaterHeaterFeatures.HOT_WATER_TEMP,
        name="Hot water temperature",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.TEMPERATURE,
        unit_fn=lambda x: x.temp_unit,
        entity_registry_enabled_default=False,
    ),
    ThinQSensorEntityDescription(
        key=WaterHeaterFeatures.ENERGY_CURRENT,
        name="Energy current",
        state_class=SensorStateClass.MEASUREMENT,
        device_class=SensorDeviceClass.POWER,
        native_unit_of_measurement=UnitOfPower.WATT,
    ),
)
HOOD_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DEFAULT_SENSOR,
        icon=DEFAULT_ICON,
        value_fn=lambda x: x.power_state,
    ),
)
MICROWAVE_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key=DEFAULT_SENSOR,
        icon=DEFAULT_ICON,
        value_fn=lambda x: x.power_state,
    ),
    ThinQSensorEntityDescription(
        key=MicroWaveFeatures.OVEN_UPPER_STATE,
        name="Oven state",
        icon=DEFAULT_ICON,
    ),
    ThinQSensorEntityDescription(
        key=MicroWaveFeatures.OVEN_UPPER_MODE,
        name="Oven mode",
        icon="mdi:inbox-full",
    ),
)

SENSOR_ENTITIES = {
    DeviceType.AC: AC_SENSORS,
    DeviceType.AIR_PURIFIER: AIR_PURIFIER_SENSORS,
    DeviceType.DEHUMIDIFIER: DEHUMIDIFIER_SENSORS,
    DeviceType.HOOD: HOOD_SENSORS,
    DeviceType.MICROWAVE: MICROWAVE_SENSORS,
    DeviceType.RANGE: RANGE_SENSORS,
    DeviceType.REFRIGERATOR: REFRIGERATOR_SENSORS,
    DeviceType.WATER_HEATER: WATER_HEATER_SENSORS,
    **{dev_type: WASH_DEV_SENSORS for dev_type in WASH_DEVICE_TYPES},
}

COMMON_SENSORS: tuple[ThinQSensorEntityDescription, ...] = (
    ThinQSensorEntityDescription(
        key="ssid",
        name="SSID",
        icon="mdi:access-point-network",
        entity_category=EntityCategory.DIAGNOSTIC,
        value_fn=lambda x: x.ssid,
    ),
)


def _sensor_exist(
    lge_device: LGEDevice, sensor_desc: ThinQSensorEntityDescription
) -> bool:
    """Check if a sensor exist for device."""
    if sensor_desc.value_fn is not None:
        return True

    feature = sensor_desc.key
    if feature in lge_device.available_features:
        return True

    return False


async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up the LGE sensors."""
    entry_config = hass.data[DOMAIN]
    lge_cfg_devices = entry_config.get(LGE_DEVICES)

    _LOGGER.debug("Starting LGE ThinQ sensors setup...")

    @callback
    def _async_discover_device(lge_devices: dict) -> None:
        """Add entities for a discovered ThinQ device."""

        if not lge_devices:
            return

        lge_sensors = [
            LGESensor(lge_device, sensor_desc, get_wrapper_device(lge_device, dev_type))
            for dev_type, sensor_descs in SENSOR_ENTITIES.items()
            for sensor_desc in sensor_descs
            for lge_device in lge_devices.get(dev_type, [])
            if _sensor_exist(lge_device, sensor_desc)
        ]

        lge_common_sensors = [
            LGESensor(lge_device, sensor_desc, get_wrapper_device(lge_device, dev_type))
            for sensor_desc in COMMON_SENSORS
            for dev_type in lge_devices.keys()
            for lge_device in lge_devices.get(dev_type, [])
        ]

        async_add_entities(lge_sensors + lge_common_sensors)

    _async_discover_device(lge_cfg_devices)

    entry.async_on_unload(
        async_dispatcher_connect(hass, LGE_DISCOVERY_NEW, _async_discover_device)
    )

    # register services
    platform = current_platform.get()
    platform.async_register_entity_service(
        SERVICE_REMOTE_START,
        {vol.Optional("course"): str},
        "async_remote_start",
        [SUPPORT_WM_SERVICES],
    )
    platform.async_register_entity_service(
        SERVICE_WAKE_UP,
        {},
        "async_wake_up",
        [SUPPORT_WM_SERVICES],
    )
    platform.async_register_entity_service(
        SERVICE_SET_TIME,
        {vol.Optional("time_wanted"): cv.time},
        "async_set_time",
        [SUPPORT_SET_TIME],
    )


class LGESensor(CoordinatorEntity, SensorEntity):
    """Class to monitor sensors for LGE device"""

    entity_description: ThinQSensorEntityDescription
    _attr_has_entity_name = True
    _wrap_device: LGEBaseDevice | None

    def __init__(
        self,
        api: LGEDevice,
        description: ThinQSensorEntityDescription,
        wrapped_device: LGEBaseDevice | None = None,
    ):
        """Initialize the sensor."""
        super().__init__(api.coordinator)
        self._api = api
        self._wrap_device = wrapped_device
        self.entity_description = description
        self._attr_unique_id = api.unique_id
        if description.key != DEFAULT_SENSOR:
            self._attr_unique_id += f"-{description.key}"
        self._attr_device_info = api.device_info
        if not description.translation_key and description.name is UNDEFINED:
            self._attr_name = get_entity_name(api, description.key)
        self._is_default = description.key == DEFAULT_SENSOR

    @property
    def supported_features(self) -> int:
        features = 0
        if self._is_default:
            if self._api.type in WM_DEVICE_TYPES:
                features |= SUPPORT_WM_SERVICES
            if self._api.type in SET_TIME_DEVICE_TYPES:
                features |= SUPPORT_SET_TIME
        return features

    @property
    def native_value(self) -> float | int | str | None:
        """Return the state of the sensor."""
        if not self.available:
            return STATE_UNAVAILABLE
        return self._get_sensor_state()

    @property
    def native_unit_of_measurement(self) -> str | None:
        """Return the unit of measurement of the sensor, if any."""
        if self._wrap_device and self.entity_description.unit_fn is not None:
            return self.entity_description.unit_fn(self._wrap_device)
        return super().native_unit_of_measurement

    @property
    def icon(self):
        """Return the icon to use in the frontend, if any."""
        ent_icon = self.entity_description.icon
        if ent_icon and ent_icon == DEFAULT_ICON:
            return DEVICE_ICONS.get(self._api.type)
        return super().icon

    @property
    def available(self) -> bool:
        """Return True if entity is available."""
        return self._api.available

    @property
    def assumed_state(self) -> bool:
        """Return True if unable to access real state of the entity."""
        return self._api.assumed_state

    @property
    def extra_state_attributes(self):
        """Return the optional state attributes."""
        if self._is_default and self._wrap_device:
            return self._wrap_device.extra_state_attributes

        features = self.entity_description.feature_attributes
        if not (features and self._api.state):
            return None
        data = {}
        for key, feat in features.items():
            if (val := self._api.state.device_features.get(feat)) is not None:
                data[key] = val
        return data

    def _get_sensor_state(self):
        """Get current sensor state"""
        if self._wrap_device and self.entity_description.value_fn is not None:
            return self.entity_description.value_fn(self._wrap_device)

        if self._api.state:
            feature = self.entity_description.key
            return self._api.state.device_features.get(feature)

        return None

    async def async_remote_start(self, course: str | None = None):
        """Call the remote start command for WM devices."""
        if self._api.type not in WM_DEVICE_TYPES:
            raise NotImplementedError()
        await self._api.device.remote_start(course)

    async def async_wake_up(self):
        """Call the wakeup command for WM devices."""
        if self._api.type not in WM_DEVICE_TYPES:
            raise NotImplementedError()
        await self._api.device.wake_up()

    async def async_set_time(self, time_wanted: time | None = None):
        """Call the set time command for Microwave devices."""
        if self._api.type not in SET_TIME_DEVICE_TYPES:
            raise NotImplementedError()
        await self._api.device.set_time(time_wanted)