Compare commits
19 commits
Author | SHA1 | Date | |
---|---|---|---|
|
22ca247de7 | ||
|
2cd2d8f9c4 | ||
|
c5c5778c0a | ||
|
371a0d574d | ||
|
ce582791db | ||
|
0b6f55eab9 | ||
|
ec30080225 | ||
|
47312793f8 | ||
|
1a12a0c1d8 | ||
|
a8974cc676 | ||
|
62ecd50910 | ||
|
6992661554 | ||
|
bc71673ea3 | ||
|
3fbc4c49f3 | ||
|
b1cf70d3a0 | ||
|
f09e4316d7 | ||
|
cd7ac53e0f | ||
|
527cd368f0 | ||
|
0177313595 |
19 changed files with 3429 additions and 32 deletions
|
@ -3,31 +3,58 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
|
||||
from thinqconnect import ThinQApi, ThinQAPIException
|
||||
from thinqconnect.integration import async_get_ha_bridge_list
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_COUNTRY, Platform
|
||||
from homeassistant.const import (
|
||||
CONF_ACCESS_TOKEN,
|
||||
CONF_COUNTRY,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
from .const import CONF_CONNECT_CLIENT_ID
|
||||
from .const import CONF_CONNECT_CLIENT_ID, MQTT_SUBSCRIPTION_INTERVAL
|
||||
from .coordinator import DeviceDataUpdateCoordinator, async_setup_device_coordinator
|
||||
from .mqtt import ThinQMQTT
|
||||
|
||||
type ThinqConfigEntry = ConfigEntry[dict[str, DeviceDataUpdateCoordinator]]
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SWITCH]
|
||||
@dataclass(kw_only=True)
|
||||
class ThinqData:
|
||||
"""A class that holds runtime data."""
|
||||
|
||||
coordinators: dict[str, DeviceDataUpdateCoordinator] = field(default_factory=dict)
|
||||
mqtt_client: ThinQMQTT | None = None
|
||||
|
||||
|
||||
type ThinqConfigEntry = ConfigEntry[ThinqData]
|
||||
|
||||
PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.CLIMATE,
|
||||
Platform.EVENT,
|
||||
Platform.FAN,
|
||||
Platform.NUMBER,
|
||||
Platform.SELECT,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.VACUUM,
|
||||
]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ThinqConfigEntry) -> bool:
|
||||
"""Set up an entry."""
|
||||
entry.runtime_data = {}
|
||||
entry.runtime_data = ThinqData()
|
||||
|
||||
access_token = entry.data[CONF_ACCESS_TOKEN]
|
||||
client_id = entry.data[CONF_CONNECT_CLIENT_ID]
|
||||
|
@ -46,6 +73,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ThinqConfigEntry) -> boo
|
|||
# Set up all platforms for this device/entry.
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
# Set up MQTT connection.
|
||||
await async_setup_mqtt(hass, entry, thinq_api, client_id)
|
||||
|
||||
# Clean up devices they are no longer in use.
|
||||
async_cleanup_device_registry(hass, entry)
|
||||
|
||||
|
@ -74,14 +104,15 @@ async def async_setup_coordinators(
|
|||
]
|
||||
task_result = await asyncio.gather(*task_list)
|
||||
for coordinator in task_result:
|
||||
entry.runtime_data[coordinator.unique_id] = coordinator
|
||||
entry.runtime_data.coordinators[coordinator.unique_id] = coordinator
|
||||
|
||||
|
||||
@callback
|
||||
def async_cleanup_device_registry(hass: HomeAssistant, entry: ThinqConfigEntry) -> None:
|
||||
"""Clean up device registry."""
|
||||
new_device_unique_ids = [
|
||||
coordinator.unique_id for coordinator in entry.runtime_data.values()
|
||||
coordinator.unique_id
|
||||
for coordinator in entry.runtime_data.coordinators.values()
|
||||
]
|
||||
device_registry = dr.async_get(hass)
|
||||
existing_entries = dr.async_entries_for_config_entry(
|
||||
|
@ -96,6 +127,40 @@ def async_cleanup_device_registry(hass: HomeAssistant, entry: ThinqConfigEntry)
|
|||
_LOGGER.debug("Remove device_registry: device_id=%s", old_entry.id)
|
||||
|
||||
|
||||
async def async_setup_mqtt(
|
||||
hass: HomeAssistant, entry: ThinqConfigEntry, thinq_api: ThinQApi, client_id: str
|
||||
) -> None:
|
||||
"""Set up MQTT connection."""
|
||||
mqtt_client = ThinQMQTT(hass, thinq_api, client_id, entry.runtime_data.coordinators)
|
||||
entry.runtime_data.mqtt_client = mqtt_client
|
||||
|
||||
# Try to connect.
|
||||
result = await mqtt_client.async_connect()
|
||||
if not result:
|
||||
_LOGGER.error("Failed to set up mqtt connection")
|
||||
return
|
||||
|
||||
# Ready to subscribe.
|
||||
await mqtt_client.async_start_subscribes()
|
||||
|
||||
entry.async_on_unload(
|
||||
async_track_time_interval(
|
||||
hass,
|
||||
mqtt_client.async_refresh_subscribe,
|
||||
MQTT_SUBSCRIPTION_INTERVAL,
|
||||
cancel_on_shutdown=True,
|
||||
)
|
||||
)
|
||||
entry.async_on_unload(
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STOP, mqtt_client.async_disconnect
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ThinqConfigEntry) -> bool:
|
||||
"""Unload the entry."""
|
||||
if entry.runtime_data.mqtt_client:
|
||||
await entry.runtime_data.mqtt_client.async_disconnect()
|
||||
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
|
|
@ -140,7 +140,7 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up an entry for binary sensor platform."""
|
||||
entities: list[ThinQBinarySensorEntity] = []
|
||||
for coordinator in entry.runtime_data.values():
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_BINARY_SENSOR_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
|
|
334
homeassistant/components/lg_thinq/climate.py
Normal file
334
homeassistant/components/lg_thinq/climate.py
Normal file
|
@ -0,0 +1,334 @@
|
|||
"""Support for climate entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.integration import ExtendedProperty
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
FAN_OFF,
|
||||
ClimateEntity,
|
||||
ClimateEntityDescription,
|
||||
ClimateEntityFeature,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.temperature import display_temp
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
from .entity import ThinQEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ThinQClimateEntityDescription(ClimateEntityDescription):
|
||||
"""Describes ThinQ climate entity."""
|
||||
|
||||
min_temp: float | None = None
|
||||
max_temp: float | None = None
|
||||
step: float | None = None
|
||||
|
||||
|
||||
DEVIE_TYPE_CLIMATE_MAP: dict[DeviceType, tuple[ThinQClimateEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (
|
||||
ThinQClimateEntityDescription(
|
||||
key=ExtendedProperty.CLIMATE_AIR_CONDITIONER,
|
||||
name=None,
|
||||
translation_key=ExtendedProperty.CLIMATE_AIR_CONDITIONER,
|
||||
),
|
||||
),
|
||||
DeviceType.SYSTEM_BOILER: (
|
||||
ThinQClimateEntityDescription(
|
||||
key=ExtendedProperty.CLIMATE_SYSTEM_BOILER,
|
||||
name=None,
|
||||
min_temp=16,
|
||||
max_temp=30,
|
||||
step=1,
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
STR_TO_HVAC: dict[str, HVACMode] = {
|
||||
"air_dry": HVACMode.DRY,
|
||||
"auto": HVACMode.AUTO,
|
||||
"cool": HVACMode.COOL,
|
||||
"fan": HVACMode.FAN_ONLY,
|
||||
"heat": HVACMode.HEAT,
|
||||
}
|
||||
|
||||
HVAC_TO_STR: dict[HVACMode, str] = {
|
||||
HVACMode.AUTO: "auto",
|
||||
HVACMode.COOL: "cool",
|
||||
HVACMode.DRY: "air_dry",
|
||||
HVACMode.FAN_ONLY: "fan",
|
||||
HVACMode.HEAT: "heat",
|
||||
}
|
||||
|
||||
THINQ_PRESET_MODE: list[str] = ["air_clean", "aroma", "energy_saving"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for climate platform."""
|
||||
entities: list[ThinQClimateEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVIE_TYPE_CLIMATE_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQClimateEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(description.key)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQClimateEntity(ThinQEntity, ClimateEntity):
|
||||
"""Represent a thinq climate platform."""
|
||||
|
||||
entity_description: ThinQClimateEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: DeviceDataUpdateCoordinator,
|
||||
entity_description: ThinQClimateEntityDescription,
|
||||
property_id: str,
|
||||
) -> None:
|
||||
"""Initialize a climate entity."""
|
||||
super().__init__(coordinator, entity_description, property_id)
|
||||
|
||||
self._attr_supported_features = (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
)
|
||||
self._attr_hvac_modes = [HVACMode.OFF]
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_preset_modes = []
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
self._requested_hvac_mode: str | None = None
|
||||
|
||||
# Set up HVAC modes.
|
||||
for mode in self.data.hvac_modes:
|
||||
if mode in STR_TO_HVAC:
|
||||
self._attr_hvac_modes.append(STR_TO_HVAC[mode])
|
||||
elif mode in THINQ_PRESET_MODE:
|
||||
self._attr_preset_modes.append(mode)
|
||||
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
|
||||
|
||||
# Set up fan modes.
|
||||
self._attr_fan_modes = self.data.fan_modes
|
||||
if self.fan_modes:
|
||||
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
|
||||
|
||||
# Supports target temperature range.
|
||||
if self.data.support_temperature_range:
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
)
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
# Update fan, hvac and preset mode.
|
||||
if self.data.is_on:
|
||||
if self.supported_features & ClimateEntityFeature.FAN_MODE:
|
||||
self._attr_fan_mode = self.data.fan_mode
|
||||
|
||||
hvac_mode = self._requested_hvac_mode or self.data.hvac_mode
|
||||
if hvac_mode in STR_TO_HVAC:
|
||||
self._attr_hvac_mode = STR_TO_HVAC.get(hvac_mode)
|
||||
self._attr_preset_mode = None
|
||||
elif hvac_mode in THINQ_PRESET_MODE:
|
||||
self._attr_preset_mode = hvac_mode
|
||||
else:
|
||||
if self.supported_features & ClimateEntityFeature.FAN_MODE:
|
||||
self._attr_fan_mode = FAN_OFF
|
||||
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
self._attr_preset_mode = None
|
||||
|
||||
self.reset_requested_hvac_mode()
|
||||
self._attr_current_humidity = self.data.humidity
|
||||
self._attr_current_temperature = self.data.current_temp
|
||||
|
||||
if (max_temp := self.entity_description.max_temp) is not None or (
|
||||
max_temp := self.data.max
|
||||
) is not None:
|
||||
self._attr_max_temp = max_temp
|
||||
if (min_temp := self.entity_description.min_temp) is not None or (
|
||||
min_temp := self.data.min
|
||||
) is not None:
|
||||
self._attr_min_temp = min_temp
|
||||
if (step := self.entity_description.step) is not None or (
|
||||
step := self.data.step
|
||||
) is not None:
|
||||
self._attr_target_temperature_step = step
|
||||
|
||||
# Update target temperatures.
|
||||
if (
|
||||
self.supported_features & ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
and self.hvac_mode == HVACMode.AUTO
|
||||
):
|
||||
self._attr_target_temperature = None
|
||||
self._attr_target_temperature_high = self.data.target_temp_high
|
||||
self._attr_target_temperature_low = self.data.target_temp_low
|
||||
else:
|
||||
self._attr_target_temperature = self.data.target_temp
|
||||
self._attr_target_temperature_high = None
|
||||
self._attr_target_temperature_low = None
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s/%s -> %s/%s, hvac:%s, unit:%s, step:%s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.current_temp,
|
||||
self.data.target_temp,
|
||||
self.current_temperature,
|
||||
self.target_temperature,
|
||||
self.hvac_mode,
|
||||
self.temperature_unit,
|
||||
self.target_temperature_step,
|
||||
)
|
||||
|
||||
def reset_requested_hvac_mode(self) -> None:
|
||||
"""Cancel request to set hvac mode."""
|
||||
self._requested_hvac_mode = None
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_on", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_on(self.property_id))
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the entity off."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_off", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_off(self.property_id))
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.async_turn_off()
|
||||
return
|
||||
|
||||
# If device is off, turn on first.
|
||||
if not self.data.is_on:
|
||||
await self.async_turn_on()
|
||||
|
||||
# When we request hvac mode while turning on the device, the previously set
|
||||
# hvac mode is displayed first and then switches to the requested hvac mode.
|
||||
# To prevent this, set the requested hvac mode here so that it will be set
|
||||
# immediately on the next update.
|
||||
self._requested_hvac_mode = HVAC_TO_STR.get(hvac_mode)
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_hvac_mode: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
hvac_mode,
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_hvac_mode(
|
||||
self.property_id, self._requested_hvac_mode
|
||||
),
|
||||
self.reset_requested_hvac_mode,
|
||||
)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set new preset mode."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_preset_mode: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
preset_mode,
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_hvac_mode(self.property_id, preset_mode)
|
||||
)
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new target fan mode."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_fan_mode: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
fan_mode,
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_fan_mode(self.property_id, fan_mode)
|
||||
)
|
||||
|
||||
def _round_by_step(self, temperature: float) -> float:
|
||||
"""Round the value by step."""
|
||||
if (
|
||||
target_temp := display_temp(
|
||||
self.coordinator.hass,
|
||||
temperature,
|
||||
self.coordinator.hass.config.units.temperature_unit,
|
||||
self.target_temperature_step or 1,
|
||||
)
|
||||
) is not None:
|
||||
return target_temp
|
||||
|
||||
return temperature
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_temperature: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
kwargs,
|
||||
)
|
||||
|
||||
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None:
|
||||
if (
|
||||
target_temp := self._round_by_step(temperature)
|
||||
) != self.target_temperature:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_target_temperature(
|
||||
self.property_id, target_temp
|
||||
)
|
||||
)
|
||||
|
||||
if (temperature_low := kwargs.get(ATTR_TARGET_TEMP_LOW)) is not None:
|
||||
if (
|
||||
target_temp_low := self._round_by_step(temperature_low)
|
||||
) != self.target_temperature_low:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_target_temperature_low(
|
||||
self.property_id, target_temp_low
|
||||
)
|
||||
)
|
||||
|
||||
if (temperature_high := kwargs.get(ATTR_TARGET_TEMP_HIGH)) is not None:
|
||||
if (
|
||||
target_temp_high := self._round_by_step(temperature_high)
|
||||
) != self.target_temperature_high:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_target_temperature_high(
|
||||
self.property_id, target_temp_high
|
||||
)
|
||||
)
|
|
@ -1,5 +1,6 @@
|
|||
"""Constants for LG ThinQ."""
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Final
|
||||
|
||||
# Config flow
|
||||
|
@ -10,3 +11,10 @@ THINQ_DEFAULT_NAME: Final = "LG ThinQ"
|
|||
THINQ_PAT_URL: Final = "https://connect-pat.lgthinq.com"
|
||||
CLIENT_PREFIX: Final = "home-assistant"
|
||||
CONF_CONNECT_CLIENT_ID: Final = "connect_client_id"
|
||||
|
||||
# MQTT
|
||||
MQTT_SUBSCRIPTION_INTERVAL: Final = timedelta(days=1)
|
||||
|
||||
# MQTT: Message types
|
||||
DEVICE_PUSH_MESSAGE: Final = "DEVICE_PUSH"
|
||||
DEVICE_STATUS_MESSAGE: Final = "DEVICE_STATUS"
|
||||
|
|
|
@ -57,6 +57,18 @@ class DeviceDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||
"""Refresh current status."""
|
||||
self.async_set_updated_data(self.data)
|
||||
|
||||
def handle_update_status(self, status: dict[str, Any]) -> None:
|
||||
"""Handle the status received from the mqtt connection."""
|
||||
data = self.api.update_status(status)
|
||||
if data is not None:
|
||||
self.async_set_updated_data(data)
|
||||
|
||||
def handle_notification_message(self, message: str | None) -> None:
|
||||
"""Handle the status received from the mqtt connection."""
|
||||
data = self.api.update_notification(message)
|
||||
if data is not None:
|
||||
self.async_set_updated_data(data)
|
||||
|
||||
|
||||
async def async_setup_device_coordinator(
|
||||
hass: HomeAssistant, ha_bridge: HABridge
|
||||
|
|
|
@ -105,11 +105,10 @@ class ThinQEntity(CoordinatorEntity[DeviceDataUpdateCoordinator]):
|
|||
except ThinQAPIException as exc:
|
||||
if on_fail_method:
|
||||
on_fail_method()
|
||||
|
||||
raise ServiceValidationError(
|
||||
exc.message,
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=exc.code,
|
||||
exc.message, translation_domain=DOMAIN, translation_key=exc.code
|
||||
) from exc
|
||||
finally:
|
||||
await self.coordinator.async_request_refresh()
|
||||
except ValueError as exc:
|
||||
if on_fail_method:
|
||||
on_fail_method()
|
||||
raise ServiceValidationError(exc) from exc
|
||||
|
|
115
homeassistant/components/lg_thinq/event.py
Normal file
115
homeassistant/components/lg_thinq/event.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
"""Support for event entity."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.integration import ActiveMode, ThinQPropertyEx
|
||||
|
||||
from homeassistant.components.event import EventEntity, EventEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
from .entity import ThinQEntity
|
||||
|
||||
NOTIFICATION_EVENT_DESC = EventEntityDescription(
|
||||
key=ThinQPropertyEx.NOTIFICATION,
|
||||
translation_key=ThinQPropertyEx.NOTIFICATION,
|
||||
)
|
||||
ERROR_EVENT_DESC = EventEntityDescription(
|
||||
key=ThinQPropertyEx.ERROR,
|
||||
translation_key=ThinQPropertyEx.ERROR,
|
||||
)
|
||||
ALL_EVENTS: tuple[EventEntityDescription, ...] = (
|
||||
ERROR_EVENT_DESC,
|
||||
NOTIFICATION_EVENT_DESC,
|
||||
)
|
||||
DEVICE_TYPE_EVENT_MAP: dict[DeviceType, tuple[EventEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.AIR_PURIFIER_FAN: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.AIR_PURIFIER: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.DEHUMIDIFIER: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.DISH_WASHER: ALL_EVENTS,
|
||||
DeviceType.DRYER: ALL_EVENTS,
|
||||
DeviceType.HUMIDIFIER: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.KIMCHI_REFRIGERATOR: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.MICROWAVE_OVEN: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.OVEN: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.REFRIGERATOR: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.ROBOT_CLEANER: ALL_EVENTS,
|
||||
DeviceType.STICK_CLEANER: (NOTIFICATION_EVENT_DESC,),
|
||||
DeviceType.STYLER: ALL_EVENTS,
|
||||
DeviceType.WASHCOMBO_MAIN: ALL_EVENTS,
|
||||
DeviceType.WASHCOMBO_MINI: ALL_EVENTS,
|
||||
DeviceType.WASHER: ALL_EVENTS,
|
||||
DeviceType.WASHTOWER_DRYER: ALL_EVENTS,
|
||||
DeviceType.WASHTOWER: ALL_EVENTS,
|
||||
DeviceType.WASHTOWER_WASHER: ALL_EVENTS,
|
||||
DeviceType.WINE_CELLAR: (NOTIFICATION_EVENT_DESC,),
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for event platform."""
|
||||
entities: list[ThinQEventEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_EVENT_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQEventEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(
|
||||
description.key, ActiveMode.READ_ONLY
|
||||
)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQEventEntity(ThinQEntity, EventEntity):
|
||||
"""Represent an thinq event platform."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: DeviceDataUpdateCoordinator,
|
||||
entity_description: EventEntityDescription,
|
||||
property_id: str,
|
||||
) -> None:
|
||||
"""Initialize an event platform."""
|
||||
super().__init__(coordinator, entity_description, property_id)
|
||||
|
||||
# For event types.
|
||||
self._attr_event_types = self.data.options
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s, event_types=%s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.value,
|
||||
self.event_types,
|
||||
)
|
||||
# Handle an event.
|
||||
if (value := self.data.value) is not None and value in self.event_types:
|
||||
self._async_handle_update(value)
|
||||
|
||||
def _async_handle_update(self, value: str) -> None:
|
||||
"""Handle the event."""
|
||||
self._trigger_event(value)
|
||||
self.async_write_ha_state()
|
150
homeassistant/components/lg_thinq/fan.py
Normal file
150
homeassistant/components/lg_thinq/fan.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
"""Support for fan entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.integration import ExtendedProperty
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
FanEntity,
|
||||
FanEntityDescription,
|
||||
FanEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util.percentage import (
|
||||
ordered_list_item_to_percentage,
|
||||
percentage_to_ordered_list_item,
|
||||
)
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
from .entity import ThinQEntity
|
||||
|
||||
DEVICE_TYPE_FAN_MAP: dict[DeviceType, tuple[FanEntityDescription, ...]] = {
|
||||
DeviceType.CEILING_FAN: (
|
||||
FanEntityDescription(
|
||||
key=ExtendedProperty.FAN,
|
||||
name=None,
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
FOUR_STEP_SPEEDS = ["low", "mid", "high", "turbo"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for fan platform."""
|
||||
entities: list[ThinQFanEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_FAN_MAP.get(coordinator.api.device.device_type)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQFanEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(description.key)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQFanEntity(ThinQEntity, FanEntity):
|
||||
"""Represent a thinq fan platform."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: DeviceDataUpdateCoordinator,
|
||||
entity_description: FanEntityDescription,
|
||||
property_id: str,
|
||||
) -> None:
|
||||
"""Initialize fan platform."""
|
||||
super().__init__(coordinator, entity_description, property_id)
|
||||
|
||||
self._ordered_named_fan_speeds = []
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
|
||||
if (fan_modes := self.data.fan_modes) is not None:
|
||||
self._attr_speed_count = len(fan_modes)
|
||||
if self.speed_count == 4:
|
||||
self._ordered_named_fan_speeds = FOUR_STEP_SPEEDS
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
# Update power on state.
|
||||
self._attr_is_on = self.data.is_on
|
||||
|
||||
# Update fan speed.
|
||||
if (
|
||||
self.data.is_on
|
||||
and (mode := self.data.fan_mode) in self._ordered_named_fan_speeds
|
||||
):
|
||||
self._attr_percentage = ordered_list_item_to_percentage(
|
||||
self._ordered_named_fan_speeds, mode
|
||||
)
|
||||
else:
|
||||
self._attr_percentage = 0
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s -> %s (percntage=%s)",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.is_on,
|
||||
self.is_on,
|
||||
self.percentage,
|
||||
)
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the speed percentage of the fan."""
|
||||
if percentage == 0:
|
||||
await self.async_turn_off()
|
||||
return
|
||||
try:
|
||||
value = percentage_to_ordered_list_item(
|
||||
self._ordered_named_fan_speeds, percentage
|
||||
)
|
||||
except ValueError:
|
||||
_LOGGER.exception("Failed to async_set_percentage")
|
||||
return
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_percentage. percntage=%s, value=%s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
percentage,
|
||||
value,
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_fan_mode(self.property_id, value)
|
||||
)
|
||||
|
||||
async def async_turn_on(
|
||||
self,
|
||||
percentage: int | None = None,
|
||||
preset_mode: str | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Turn on the fan."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_on", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_on(self.property_id))
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the fan off."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_off", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_off(self.property_id))
|
|
@ -1,8 +1,44 @@
|
|||
{
|
||||
"entity": {
|
||||
"switch": {
|
||||
"auto_mode": {
|
||||
"default": "mdi:cogs"
|
||||
},
|
||||
"express_mode": {
|
||||
"default": "mdi:snowflake-variant"
|
||||
},
|
||||
"hot_water_mode": {
|
||||
"default": "mdi:list-status"
|
||||
},
|
||||
"humidity_warm_mode": {
|
||||
"default": "mdi:heat-wave"
|
||||
},
|
||||
"hygiene_dry_mode": {
|
||||
"default": "mdi:format-list-bulleted"
|
||||
},
|
||||
"mood_lamp_state": {
|
||||
"default": "mdi:lamp"
|
||||
},
|
||||
"operation_power": {
|
||||
"default": "mdi:power"
|
||||
},
|
||||
"optimal_humidity": {
|
||||
"default": "mdi:water-percent"
|
||||
},
|
||||
"power_save_enabled": {
|
||||
"default": "mdi:hydro-power"
|
||||
},
|
||||
"rapid_freeze": {
|
||||
"default": "mdi:snowflake"
|
||||
},
|
||||
"sleep_mode": {
|
||||
"default": "mdi:format-list-bulleted"
|
||||
},
|
||||
"uv_nano": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"warm_mode": {
|
||||
"default": "mdi:heat-wave"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
|
@ -39,6 +75,333 @@
|
|||
"one_touch_filter": {
|
||||
"default": "mdi:air-filter"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"climate_air_conditioner": {
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"slow": "mdi:fan-chevron-down",
|
||||
"low": "mdi:fan-speed-1",
|
||||
"mid": "mdi:fan-speed-2",
|
||||
"high": "mdi:fan-speed-3",
|
||||
"power": "mdi:fan-chevron-up",
|
||||
"auto": "mdi:fan-auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"event": {
|
||||
"error": {
|
||||
"default": "mdi:alert-circle-outline"
|
||||
},
|
||||
"notification": {
|
||||
"default": "mdi:message-badge-outline"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"target_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"target_temperature_for_location": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"light_status": {
|
||||
"default": "mdi:television-ambient-light"
|
||||
},
|
||||
"fan_speed": {
|
||||
"default": "mdi:wind-power-outline"
|
||||
},
|
||||
"lamp_brightness": {
|
||||
"default": "mdi:alarm-light-outline"
|
||||
},
|
||||
"wind_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"relative_hour_to_start": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_start_for_location": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_start_wm": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_start_wm_for_location": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_stop": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_stop_for_location": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_stop_wm": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"relative_hour_to_stop_wm_for_location": {
|
||||
"default": "mdi:timer-edit-outline"
|
||||
},
|
||||
"sleep_timer_relative_hour_to_stop": {
|
||||
"default": "mdi:bed-clock"
|
||||
},
|
||||
"sleep_timer_relative_hour_to_stop_for_location": {
|
||||
"default": "mdi:bed-clock"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"wind_strength": {
|
||||
"default": "mdi:wind-power-outline"
|
||||
},
|
||||
"monitoring_enabled": {
|
||||
"default": "mdi:monitor-eye"
|
||||
},
|
||||
"current_job_mode": {
|
||||
"default": "mdi:format-list-bulleted"
|
||||
},
|
||||
"operation_mode": {
|
||||
"default": "mdi:gesture-tap-button"
|
||||
},
|
||||
"operation_mode_for_location": {
|
||||
"default": "mdi:gesture-tap-button"
|
||||
},
|
||||
"air_clean_operation_mode": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"cook_mode": {
|
||||
"default": "mdi:chef-hat"
|
||||
},
|
||||
"cook_mode_for_location": {
|
||||
"default": "mdi:chef-hat"
|
||||
},
|
||||
"light_brightness": {
|
||||
"default": "mdi:list-status"
|
||||
},
|
||||
"wind_angle": {
|
||||
"default": "mdi:rotate-360"
|
||||
},
|
||||
"display_light": {
|
||||
"default": "mdi:brightness-6"
|
||||
},
|
||||
"fresh_air_filter": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"hygiene_dry_mode": {
|
||||
"default": "mdi:format-list-bulleted"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"odor_level": {
|
||||
"default": "mdi:scent"
|
||||
},
|
||||
"current_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"total_pollution_level": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"monitoring_enabled": {
|
||||
"default": "mdi:monitor-eye"
|
||||
},
|
||||
"growth_mode": {
|
||||
"default": "mdi:sprout-outline"
|
||||
},
|
||||
"growth_mode_for_location": {
|
||||
"default": "mdi:sprout-outline"
|
||||
},
|
||||
"wind_volume": {
|
||||
"default": "mdi:wind-power-outline"
|
||||
},
|
||||
"wind_volume_for_location": {
|
||||
"default": "mdi:wind-power-outline"
|
||||
},
|
||||
"brightness": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"brightness_for_location": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"duration": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"duration_for_location": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"day_target_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"day_target_temperature_for_location": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"night_target_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"night_target_temperature_for_location": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"temperature_state": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"temperature_state_for_location": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"current_state": {
|
||||
"default": "mdi:list-status"
|
||||
},
|
||||
"current_state_for_location": {
|
||||
"default": "mdi:list-status"
|
||||
},
|
||||
"fresh_air_filter": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"filter_lifetime": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"used_time": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"current_job_mode": {
|
||||
"default": "mdi:dots-circle"
|
||||
},
|
||||
"current_job_mode_stick_cleaner": {
|
||||
"default": "mdi:dots-circle"
|
||||
},
|
||||
"personalization_mode": {
|
||||
"default": "mdi:dots-circle"
|
||||
},
|
||||
"current_dish_washing_course": {
|
||||
"default": "mdi:format-list-checks"
|
||||
},
|
||||
"rinse_level": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"softening_level": {
|
||||
"default": "mdi:tune-vertical-variant"
|
||||
},
|
||||
"cock_state": {
|
||||
"default": "mdi:air-filter"
|
||||
},
|
||||
"sterilizing_state": {
|
||||
"default": "mdi:water-alert-outline"
|
||||
},
|
||||
"water_type": {
|
||||
"default": "mdi:water"
|
||||
},
|
||||
"target_temperature": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"target_temperature_for_location": {
|
||||
"default": "mdi:thermometer"
|
||||
},
|
||||
"elapsed_day_state": {
|
||||
"default": "mdi:calendar-range-outline"
|
||||
},
|
||||
"elapsed_day_total": {
|
||||
"default": "mdi:calendar-range-outline"
|
||||
},
|
||||
"recipe_name": {
|
||||
"default": "mdi:information-box-outline"
|
||||
},
|
||||
"wort_info": {
|
||||
"default": "mdi:information-box-outline"
|
||||
},
|
||||
"yeast_info": {
|
||||
"default": "mdi:information-box-outline"
|
||||
},
|
||||
"hop_oil_info": {
|
||||
"default": "mdi:information-box-outline"
|
||||
},
|
||||
"flavor_info": {
|
||||
"default": "mdi:information-box-outline"
|
||||
},
|
||||
"beer_remain": {
|
||||
"default": "mdi:glass-mug-variant"
|
||||
},
|
||||
"battery_level": {
|
||||
"default": "mdi:battery-medium"
|
||||
},
|
||||
"relative_to_start": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_start_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_start_wm": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_start_wm_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_stop": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_stop_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_stop_wm": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"relative_to_stop_wm_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"sleep_timer_relative_to_stop": {
|
||||
"default": "mdi:bed-clock"
|
||||
},
|
||||
"sleep_timer_relative_to_stop_for_location": {
|
||||
"default": "mdi:bed-clock"
|
||||
},
|
||||
"absolute_to_start": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"absolute_to_start_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"absolute_to_stop": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"absolute_to_stop_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"remain": {
|
||||
"default": "mdi:timer-sand"
|
||||
},
|
||||
"remain_for_location": {
|
||||
"default": "mdi:timer-sand"
|
||||
},
|
||||
"running": {
|
||||
"default": "mdi:timer-play-outline"
|
||||
},
|
||||
"running_for_location": {
|
||||
"default": "mdi:timer-play-outline"
|
||||
},
|
||||
"total": {
|
||||
"default": "mdi:timer-play-outline"
|
||||
},
|
||||
"total_for_location": {
|
||||
"default": "mdi:timer-play-outline"
|
||||
},
|
||||
"target": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"target_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"light_start": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"light_start_for_location": {
|
||||
"default": "mdi:clock-time-three-outline"
|
||||
},
|
||||
"power_level": {
|
||||
"default": "mdi:radiator"
|
||||
},
|
||||
"power_level_for_location": {
|
||||
"default": "mdi:radiator"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/lg_thinq/",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["thinqconnect"],
|
||||
"requirements": ["thinqconnect==0.9.7"]
|
||||
"requirements": ["thinqconnect==0.9.8"]
|
||||
}
|
||||
|
|
186
homeassistant/components/lg_thinq/mqtt.py
Normal file
186
homeassistant/components/lg_thinq/mqtt.py
Normal file
|
@ -0,0 +1,186 @@
|
|||
"""Support for LG ThinQ Connect API."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from thinqconnect import (
|
||||
DeviceType,
|
||||
ThinQApi,
|
||||
ThinQAPIErrorCodes,
|
||||
ThinQAPIException,
|
||||
ThinQMQTTClient,
|
||||
)
|
||||
|
||||
from homeassistant.core import Event, HomeAssistant
|
||||
|
||||
from .const import DEVICE_PUSH_MESSAGE, DEVICE_STATUS_MESSAGE
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ThinQMQTT:
|
||||
"""A class that implements MQTT connection."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
thinq_api: ThinQApi,
|
||||
client_id: str,
|
||||
coordinators: dict[str, DeviceDataUpdateCoordinator],
|
||||
) -> None:
|
||||
"""Initialize a mqtt."""
|
||||
self.hass = hass
|
||||
self.thinq_api = thinq_api
|
||||
self.client_id = client_id
|
||||
self.coordinators = coordinators
|
||||
self.client: ThinQMQTTClient | None = None
|
||||
|
||||
async def async_connect(self) -> bool:
|
||||
"""Create a mqtt client and then try to connect."""
|
||||
try:
|
||||
self.client = await ThinQMQTTClient(
|
||||
self.thinq_api, self.client_id, self.on_message_received
|
||||
)
|
||||
if self.client is None:
|
||||
return False
|
||||
|
||||
# Connect to server and create certificate.
|
||||
return await self.client.async_prepare_mqtt()
|
||||
except (ThinQAPIException, TypeError, ValueError):
|
||||
_LOGGER.exception("Failed to connect")
|
||||
return False
|
||||
|
||||
async def async_disconnect(self, event: Event | None = None) -> None:
|
||||
"""Unregister client and disconnects handlers."""
|
||||
await self.async_end_subscribes()
|
||||
|
||||
if self.client is not None:
|
||||
try:
|
||||
await self.client.async_disconnect()
|
||||
except (ThinQAPIException, TypeError, ValueError):
|
||||
_LOGGER.exception("Failed to disconnect")
|
||||
|
||||
def _get_failed_device_count(
|
||||
self, results: list[dict | BaseException | None]
|
||||
) -> int:
|
||||
"""Check if there exists errors while performing tasks and then return count."""
|
||||
# Note that result code '1207' means 'Already subscribed push'
|
||||
# and is not actually fail.
|
||||
return sum(
|
||||
isinstance(result, (TypeError, ValueError))
|
||||
or (
|
||||
isinstance(result, ThinQAPIException)
|
||||
and result.code != ThinQAPIErrorCodes.ALREADY_SUBSCRIBED_PUSH
|
||||
)
|
||||
for result in results
|
||||
)
|
||||
|
||||
async def async_refresh_subscribe(self, now: datetime | None = None) -> None:
|
||||
"""Update event subscribes."""
|
||||
_LOGGER.debug("async_refresh_subscribe: now=%s", now)
|
||||
|
||||
tasks = [
|
||||
self.hass.async_create_task(
|
||||
self.thinq_api.async_post_event_subscribe(coordinator.device_id)
|
||||
)
|
||||
for coordinator in self.coordinators.values()
|
||||
]
|
||||
if tasks:
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
if (count := self._get_failed_device_count(results)) > 0:
|
||||
_LOGGER.error("Failed to refresh subscription on %s devices", count)
|
||||
|
||||
async def async_start_subscribes(self) -> None:
|
||||
"""Start push/event subscribes."""
|
||||
_LOGGER.debug("async_start_subscribes")
|
||||
|
||||
if self.client is None:
|
||||
_LOGGER.error("Failed to start subscription: No client")
|
||||
return
|
||||
|
||||
tasks = [
|
||||
self.hass.async_create_task(
|
||||
self.thinq_api.async_post_push_subscribe(coordinator.device_id)
|
||||
)
|
||||
for coordinator in self.coordinators.values()
|
||||
]
|
||||
tasks.extend(
|
||||
self.hass.async_create_task(
|
||||
self.thinq_api.async_post_event_subscribe(coordinator.device_id)
|
||||
)
|
||||
for coordinator in self.coordinators.values()
|
||||
)
|
||||
if tasks:
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
if (count := self._get_failed_device_count(results)) > 0:
|
||||
_LOGGER.error("Failed to start subscription on %s devices", count)
|
||||
|
||||
await self.client.async_connect_mqtt()
|
||||
|
||||
async def async_end_subscribes(self) -> None:
|
||||
"""Start push/event unsubscribes."""
|
||||
_LOGGER.debug("async_end_subscribes")
|
||||
|
||||
tasks = [
|
||||
self.hass.async_create_task(
|
||||
self.thinq_api.async_delete_push_subscribe(coordinator.device_id)
|
||||
)
|
||||
for coordinator in self.coordinators.values()
|
||||
]
|
||||
tasks.extend(
|
||||
self.hass.async_create_task(
|
||||
self.thinq_api.async_delete_event_subscribe(coordinator.device_id)
|
||||
)
|
||||
for coordinator in self.coordinators.values()
|
||||
)
|
||||
if tasks:
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
if (count := self._get_failed_device_count(results)) > 0:
|
||||
_LOGGER.error("Failed to end subscription on %s devices", count)
|
||||
|
||||
def on_message_received(
|
||||
self,
|
||||
topic: str,
|
||||
payload: bytes,
|
||||
dup: bool,
|
||||
qos: Any,
|
||||
retain: bool,
|
||||
**kwargs: dict,
|
||||
) -> None:
|
||||
"""Handle the received message that matching the topic."""
|
||||
decoded = payload.decode()
|
||||
try:
|
||||
message = json.loads(decoded)
|
||||
except ValueError:
|
||||
_LOGGER.error("Failed to parse message: payload=%s", decoded)
|
||||
return
|
||||
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.async_handle_device_event(message), self.hass.loop
|
||||
).result()
|
||||
|
||||
async def async_handle_device_event(self, message: dict) -> None:
|
||||
"""Handle received mqtt message."""
|
||||
_LOGGER.debug("async_handle_device_event: message=%s", message)
|
||||
unique_id = (
|
||||
f"{message["deviceId"]}_{list(message["report"].keys())[0]}"
|
||||
if message["deviceType"] == DeviceType.WASHTOWER
|
||||
else message["deviceId"]
|
||||
)
|
||||
coordinator = self.coordinators.get(unique_id)
|
||||
if coordinator is None:
|
||||
_LOGGER.error("Failed to handle device event: No device")
|
||||
return
|
||||
|
||||
push_type = message.get("pushType")
|
||||
|
||||
if push_type == DEVICE_STATUS_MESSAGE:
|
||||
coordinator.handle_update_status(message.get("report", {}))
|
||||
elif push_type == DEVICE_PUSH_MESSAGE:
|
||||
coordinator.handle_notification_message(message.get("pushCode"))
|
214
homeassistant/components/lg_thinq/number.py
Normal file
214
homeassistant/components/lg_thinq/number.py
Normal file
|
@ -0,0 +1,214 @@
|
|||
"""Support for number entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.devices.const import Property as ThinQProperty
|
||||
from thinqconnect.integration import ActiveMode, TimerProperty
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberDeviceClass,
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
NumberMode,
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, UnitOfTemperature, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .entity import ThinQEntity
|
||||
|
||||
NUMBER_DESC: dict[ThinQProperty, NumberEntityDescription] = {
|
||||
ThinQProperty.FAN_SPEED: NumberEntityDescription(
|
||||
key=ThinQProperty.FAN_SPEED,
|
||||
translation_key=ThinQProperty.FAN_SPEED,
|
||||
),
|
||||
ThinQProperty.LAMP_BRIGHTNESS: NumberEntityDescription(
|
||||
key=ThinQProperty.LAMP_BRIGHTNESS,
|
||||
translation_key=ThinQProperty.LAMP_BRIGHTNESS,
|
||||
),
|
||||
ThinQProperty.LIGHT_STATUS: NumberEntityDescription(
|
||||
key=ThinQProperty.LIGHT_STATUS,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.LIGHT_STATUS,
|
||||
),
|
||||
ThinQProperty.TARGET_HUMIDITY: NumberEntityDescription(
|
||||
key=ThinQProperty.TARGET_HUMIDITY,
|
||||
device_class=NumberDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
ThinQProperty.TARGET_TEMPERATURE: NumberEntityDescription(
|
||||
key=ThinQProperty.TARGET_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
translation_key=ThinQProperty.TARGET_TEMPERATURE,
|
||||
),
|
||||
ThinQProperty.WIND_TEMPERATURE: NumberEntityDescription(
|
||||
key=ThinQProperty.WIND_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
translation_key=ThinQProperty.WIND_TEMPERATURE,
|
||||
),
|
||||
}
|
||||
TIMER_NUMBER_DESC: dict[ThinQProperty, NumberEntityDescription] = {
|
||||
ThinQProperty.RELATIVE_HOUR_TO_START: NumberEntityDescription(
|
||||
key=ThinQProperty.RELATIVE_HOUR_TO_START,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=ThinQProperty.RELATIVE_HOUR_TO_START,
|
||||
),
|
||||
TimerProperty.RELATIVE_HOUR_TO_START_WM: NumberEntityDescription(
|
||||
key=ThinQProperty.RELATIVE_HOUR_TO_START,
|
||||
native_min_value=0,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=TimerProperty.RELATIVE_HOUR_TO_START_WM,
|
||||
),
|
||||
ThinQProperty.RELATIVE_HOUR_TO_STOP: NumberEntityDescription(
|
||||
key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
|
||||
),
|
||||
TimerProperty.RELATIVE_HOUR_TO_STOP_WM: NumberEntityDescription(
|
||||
key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
|
||||
native_min_value=0,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=TimerProperty.RELATIVE_HOUR_TO_STOP_WM,
|
||||
),
|
||||
ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP: NumberEntityDescription(
|
||||
key=ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP,
|
||||
),
|
||||
}
|
||||
WASHER_NUMBERS: tuple[NumberEntityDescription, ...] = (
|
||||
TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_START_WM],
|
||||
TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_STOP_WM],
|
||||
)
|
||||
|
||||
DEVICE_TYPE_NUMBER_MAP: dict[DeviceType, tuple[NumberEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (
|
||||
TIMER_NUMBER_DESC[ThinQProperty.RELATIVE_HOUR_TO_START],
|
||||
TIMER_NUMBER_DESC[ThinQProperty.RELATIVE_HOUR_TO_STOP],
|
||||
TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
|
||||
),
|
||||
DeviceType.AIR_PURIFIER_FAN: (
|
||||
NUMBER_DESC[ThinQProperty.WIND_TEMPERATURE],
|
||||
TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
|
||||
),
|
||||
DeviceType.DRYER: WASHER_NUMBERS,
|
||||
DeviceType.HOOD: (
|
||||
NUMBER_DESC[ThinQProperty.LAMP_BRIGHTNESS],
|
||||
NUMBER_DESC[ThinQProperty.FAN_SPEED],
|
||||
),
|
||||
DeviceType.HUMIDIFIER: (
|
||||
NUMBER_DESC[ThinQProperty.TARGET_HUMIDITY],
|
||||
TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
|
||||
),
|
||||
DeviceType.MICROWAVE_OVEN: (
|
||||
NUMBER_DESC[ThinQProperty.LAMP_BRIGHTNESS],
|
||||
NUMBER_DESC[ThinQProperty.FAN_SPEED],
|
||||
),
|
||||
DeviceType.OVEN: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
|
||||
DeviceType.REFRIGERATOR: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
|
||||
DeviceType.STYLER: (TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_STOP_WM],),
|
||||
DeviceType.WASHCOMBO_MAIN: WASHER_NUMBERS,
|
||||
DeviceType.WASHCOMBO_MINI: WASHER_NUMBERS,
|
||||
DeviceType.WASHER: WASHER_NUMBERS,
|
||||
DeviceType.WASHTOWER_DRYER: WASHER_NUMBERS,
|
||||
DeviceType.WASHTOWER: WASHER_NUMBERS,
|
||||
DeviceType.WASHTOWER_WASHER: WASHER_NUMBERS,
|
||||
DeviceType.WATER_HEATER: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
|
||||
DeviceType.WINE_CELLAR: (
|
||||
NUMBER_DESC[ThinQProperty.LIGHT_STATUS],
|
||||
NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],
|
||||
),
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for number platform."""
|
||||
entities: list[ThinQNumberEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_NUMBER_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQNumberEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(
|
||||
description.key, ActiveMode.READ_WRITE
|
||||
)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQNumberEntity(ThinQEntity, NumberEntity):
|
||||
"""Represent a thinq number platform."""
|
||||
|
||||
_attr_mode = NumberMode.BOX
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
self._attr_native_value = self.data.value
|
||||
|
||||
# Update unit.
|
||||
if (
|
||||
unit_of_measurement := self._get_unit_of_measurement(self.data.unit)
|
||||
) is not None:
|
||||
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||
|
||||
# Undate range.
|
||||
if (
|
||||
self.entity_description.native_min_value is None
|
||||
and (min_value := self.data.min) is not None
|
||||
):
|
||||
self._attr_native_min_value = min_value
|
||||
|
||||
if (
|
||||
self.entity_description.native_max_value is None
|
||||
and (max_value := self.data.max) is not None
|
||||
):
|
||||
self._attr_native_max_value = max_value
|
||||
|
||||
if (
|
||||
self.entity_description.native_step is None
|
||||
and (step := self.data.step) is not None
|
||||
):
|
||||
self._attr_native_step = step
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s -> %s, unit:%s, min:%s, max:%s, step:%s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.value,
|
||||
self.native_value,
|
||||
self.native_unit_of_measurement,
|
||||
self.native_min_value,
|
||||
self.native_max_value,
|
||||
self.native_step,
|
||||
)
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Change to new number value."""
|
||||
if self.step.is_integer():
|
||||
value = int(value)
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_set_native_value: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
value,
|
||||
)
|
||||
|
||||
await self.async_call_api(self.coordinator.api.post(self.property_id, value))
|
207
homeassistant/components/lg_thinq/select.py
Normal file
207
homeassistant/components/lg_thinq/select.py
Normal file
|
@ -0,0 +1,207 @@
|
|||
"""Support for select entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.devices.const import Property as ThinQProperty
|
||||
from thinqconnect.integration import ActiveMode
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
from .entity import ThinQEntity
|
||||
|
||||
SELECT_DESC: dict[ThinQProperty, SelectEntityDescription] = {
|
||||
ThinQProperty.MONITORING_ENABLED: SelectEntityDescription(
|
||||
key=ThinQProperty.MONITORING_ENABLED,
|
||||
translation_key=ThinQProperty.MONITORING_ENABLED,
|
||||
),
|
||||
ThinQProperty.COOK_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.COOK_MODE,
|
||||
translation_key=ThinQProperty.COOK_MODE,
|
||||
),
|
||||
ThinQProperty.DISPLAY_LIGHT: SelectEntityDescription(
|
||||
key=ThinQProperty.DISPLAY_LIGHT,
|
||||
translation_key=ThinQProperty.DISPLAY_LIGHT,
|
||||
),
|
||||
ThinQProperty.CURRENT_JOB_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.CURRENT_JOB_MODE,
|
||||
translation_key=ThinQProperty.CURRENT_JOB_MODE,
|
||||
),
|
||||
ThinQProperty.FRESH_AIR_FILTER: SelectEntityDescription(
|
||||
key=ThinQProperty.FRESH_AIR_FILTER,
|
||||
translation_key=ThinQProperty.FRESH_AIR_FILTER,
|
||||
),
|
||||
}
|
||||
AIR_FLOW_SELECT_DESC: dict[ThinQProperty, SelectEntityDescription] = {
|
||||
ThinQProperty.WIND_STRENGTH: SelectEntityDescription(
|
||||
key=ThinQProperty.WIND_STRENGTH,
|
||||
translation_key=ThinQProperty.WIND_STRENGTH,
|
||||
),
|
||||
ThinQProperty.WIND_ANGLE: SelectEntityDescription(
|
||||
key=ThinQProperty.WIND_ANGLE,
|
||||
translation_key=ThinQProperty.WIND_ANGLE,
|
||||
),
|
||||
}
|
||||
OPERATION_SELECT_DESC: dict[ThinQProperty, SelectEntityDescription] = {
|
||||
ThinQProperty.AIR_CLEAN_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.AIR_CLEAN_OPERATION_MODE,
|
||||
translation_key="air_clean_operation_mode",
|
||||
),
|
||||
ThinQProperty.DISH_WASHER_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.DISH_WASHER_OPERATION_MODE,
|
||||
translation_key="operation_mode",
|
||||
),
|
||||
ThinQProperty.DRYER_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.DRYER_OPERATION_MODE,
|
||||
translation_key="operation_mode",
|
||||
),
|
||||
ThinQProperty.HYGIENE_DRY_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.HYGIENE_DRY_MODE,
|
||||
translation_key=ThinQProperty.HYGIENE_DRY_MODE,
|
||||
),
|
||||
ThinQProperty.LIGHT_BRIGHTNESS: SelectEntityDescription(
|
||||
key=ThinQProperty.LIGHT_BRIGHTNESS,
|
||||
translation_key=ThinQProperty.LIGHT_BRIGHTNESS,
|
||||
),
|
||||
ThinQProperty.OVEN_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.OVEN_OPERATION_MODE,
|
||||
translation_key="operation_mode",
|
||||
),
|
||||
ThinQProperty.STYLER_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.STYLER_OPERATION_MODE,
|
||||
translation_key="operation_mode",
|
||||
),
|
||||
ThinQProperty.WASHER_OPERATION_MODE: SelectEntityDescription(
|
||||
key=ThinQProperty.WASHER_OPERATION_MODE,
|
||||
translation_key="operation_mode",
|
||||
),
|
||||
}
|
||||
|
||||
DEVICE_TYPE_SELECT_MAP: dict[DeviceType, tuple[SelectEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (
|
||||
SELECT_DESC[ThinQProperty.MONITORING_ENABLED],
|
||||
OPERATION_SELECT_DESC[ThinQProperty.AIR_CLEAN_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.AIR_PURIFIER_FAN: (
|
||||
AIR_FLOW_SELECT_DESC[ThinQProperty.WIND_STRENGTH],
|
||||
AIR_FLOW_SELECT_DESC[ThinQProperty.WIND_ANGLE],
|
||||
SELECT_DESC[ThinQProperty.DISPLAY_LIGHT],
|
||||
SELECT_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
),
|
||||
DeviceType.AIR_PURIFIER: (
|
||||
AIR_FLOW_SELECT_DESC[ThinQProperty.WIND_STRENGTH],
|
||||
SELECT_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
),
|
||||
DeviceType.DEHUMIDIFIER: (AIR_FLOW_SELECT_DESC[ThinQProperty.WIND_STRENGTH],),
|
||||
DeviceType.DISH_WASHER: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.DISH_WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.DRYER: (OPERATION_SELECT_DESC[ThinQProperty.DRYER_OPERATION_MODE],),
|
||||
DeviceType.HUMIDIFIER: (
|
||||
AIR_FLOW_SELECT_DESC[ThinQProperty.WIND_STRENGTH],
|
||||
SELECT_DESC[ThinQProperty.DISPLAY_LIGHT],
|
||||
SELECT_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
OPERATION_SELECT_DESC[ThinQProperty.HYGIENE_DRY_MODE],
|
||||
),
|
||||
DeviceType.OVEN: (
|
||||
SELECT_DESC[ThinQProperty.COOK_MODE],
|
||||
OPERATION_SELECT_DESC[ThinQProperty.OVEN_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.REFRIGERATOR: (SELECT_DESC[ThinQProperty.FRESH_AIR_FILTER],),
|
||||
DeviceType.STYLER: (OPERATION_SELECT_DESC[ThinQProperty.STYLER_OPERATION_MODE],),
|
||||
DeviceType.WASHCOMBO_MAIN: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.WASHCOMBO_MINI: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.WASHER: (OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],),
|
||||
DeviceType.WASHTOWER_DRYER: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.WASHTOWER: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.DRYER_OPERATION_MODE],
|
||||
OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.WASHTOWER_WASHER: (
|
||||
OPERATION_SELECT_DESC[ThinQProperty.WASHER_OPERATION_MODE],
|
||||
),
|
||||
DeviceType.WATER_HEATER: (SELECT_DESC[ThinQProperty.CURRENT_JOB_MODE],),
|
||||
DeviceType.WINE_CELLAR: (OPERATION_SELECT_DESC[ThinQProperty.LIGHT_BRIGHTNESS],),
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for select platform."""
|
||||
entities: list[ThinQSelectEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_SELECT_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQSelectEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(
|
||||
description.key, ActiveMode.WRITABLE
|
||||
)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQSelectEntity(ThinQEntity, SelectEntity):
|
||||
"""Represent a thinq select platform."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: DeviceDataUpdateCoordinator,
|
||||
entity_description: SelectEntityDescription,
|
||||
property_id: str,
|
||||
) -> None:
|
||||
"""Initialize a select entity."""
|
||||
super().__init__(coordinator, entity_description, property_id)
|
||||
|
||||
self._attr_options = self.data.options if self.data.options is not None else []
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
if self.data.value:
|
||||
self._attr_current_option = str(self.data.value)
|
||||
else:
|
||||
self._attr_current_option = None
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s -> %s, options:%s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.value,
|
||||
self.current_option,
|
||||
self.options,
|
||||
)
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_select_option: %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
option,
|
||||
)
|
||||
await self.async_call_api(self.coordinator.api.post(self.property_id, option))
|
529
homeassistant/components/lg_thinq/sensor.py
Normal file
529
homeassistant/components/lg_thinq/sensor.py
Normal file
|
@ -0,0 +1,529 @@
|
|||
"""Support for sensor entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.devices.const import Property as ThinQProperty
|
||||
from thinqconnect.integration import ActiveMode, ThinQPropertyEx, TimerProperty
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .coordinator import DeviceDataUpdateCoordinator
|
||||
from .entity import ThinQEntity
|
||||
|
||||
AIR_QUALITY_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.PM1: SensorEntityDescription(
|
||||
key=ThinQProperty.PM1,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.PM2: SensorEntityDescription(
|
||||
key=ThinQProperty.PM2,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.PM10: SensorEntityDescription(
|
||||
key=ThinQProperty.PM10,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.HUMIDITY: SensorEntityDescription(
|
||||
key=ThinQProperty.HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.MONITORING_ENABLED: SensorEntityDescription(
|
||||
key=ThinQProperty.MONITORING_ENABLED,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.MONITORING_ENABLED,
|
||||
),
|
||||
ThinQProperty.TEMPERATURE: SensorEntityDescription(
|
||||
key=ThinQProperty.TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key=ThinQProperty.TEMPERATURE,
|
||||
),
|
||||
ThinQProperty.ODOR_LEVEL: SensorEntityDescription(
|
||||
key=ThinQProperty.ODOR_LEVEL,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.ODOR_LEVEL,
|
||||
),
|
||||
ThinQProperty.TOTAL_POLLUTION_LEVEL: SensorEntityDescription(
|
||||
key=ThinQProperty.TOTAL_POLLUTION_LEVEL,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.TOTAL_POLLUTION_LEVEL,
|
||||
),
|
||||
}
|
||||
BATTERY_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.BATTERY_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.BATTERY_PERCENT,
|
||||
translation_key=ThinQProperty.BATTERY_LEVEL,
|
||||
),
|
||||
}
|
||||
DISH_WASHING_COURSE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.CURRENT_DISH_WASHING_COURSE: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_DISH_WASHING_COURSE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.CURRENT_DISH_WASHING_COURSE,
|
||||
)
|
||||
}
|
||||
FILTER_INFO_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.FILTER_LIFETIME: SensorEntityDescription(
|
||||
key=ThinQProperty.FILTER_LIFETIME,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=ThinQProperty.FILTER_LIFETIME,
|
||||
),
|
||||
}
|
||||
HUMIDITY_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.CURRENT_HUMIDITY: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
}
|
||||
JOB_MODE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.CURRENT_JOB_MODE: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_JOB_MODE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.CURRENT_JOB_MODE,
|
||||
),
|
||||
ThinQPropertyEx.CURRENT_JOB_MODE_STICK_CLEANER: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_JOB_MODE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQPropertyEx.CURRENT_JOB_MODE_STICK_CLEANER,
|
||||
),
|
||||
ThinQProperty.PERSONALIZATION_MODE: SensorEntityDescription(
|
||||
key=ThinQProperty.PERSONALIZATION_MODE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.PERSONALIZATION_MODE,
|
||||
),
|
||||
}
|
||||
LIGHT_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.BRIGHTNESS: SensorEntityDescription(
|
||||
key=ThinQProperty.BRIGHTNESS,
|
||||
translation_key=ThinQProperty.BRIGHTNESS,
|
||||
),
|
||||
ThinQProperty.DURATION: SensorEntityDescription(
|
||||
key=ThinQProperty.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
translation_key=ThinQProperty.DURATION,
|
||||
),
|
||||
}
|
||||
POWER_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.POWER_LEVEL: SensorEntityDescription(
|
||||
key=ThinQProperty.POWER_LEVEL,
|
||||
translation_key=ThinQProperty.POWER_LEVEL,
|
||||
)
|
||||
}
|
||||
PREFERENCE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.RINSE_LEVEL: SensorEntityDescription(
|
||||
key=ThinQProperty.RINSE_LEVEL,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.RINSE_LEVEL,
|
||||
),
|
||||
ThinQProperty.SOFTENING_LEVEL: SensorEntityDescription(
|
||||
key=ThinQProperty.SOFTENING_LEVEL,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.SOFTENING_LEVEL,
|
||||
),
|
||||
}
|
||||
RECIPE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.RECIPE_NAME: SensorEntityDescription(
|
||||
key=ThinQProperty.RECIPE_NAME,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.RECIPE_NAME,
|
||||
),
|
||||
ThinQProperty.WORT_INFO: SensorEntityDescription(
|
||||
key=ThinQProperty.WORT_INFO,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.WORT_INFO,
|
||||
),
|
||||
ThinQProperty.YEAST_INFO: SensorEntityDescription(
|
||||
key=ThinQProperty.YEAST_INFO,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.YEAST_INFO,
|
||||
),
|
||||
ThinQProperty.HOP_OIL_INFO: SensorEntityDescription(
|
||||
key=ThinQProperty.HOP_OIL_INFO,
|
||||
translation_key=ThinQProperty.HOP_OIL_INFO,
|
||||
),
|
||||
ThinQProperty.FLAVOR_INFO: SensorEntityDescription(
|
||||
key=ThinQProperty.FLAVOR_INFO,
|
||||
translation_key=ThinQProperty.FLAVOR_INFO,
|
||||
),
|
||||
ThinQProperty.BEER_REMAIN: SensorEntityDescription(
|
||||
key=ThinQProperty.BEER_REMAIN,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.BEER_REMAIN,
|
||||
),
|
||||
}
|
||||
REFRIGERATION_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.FRESH_AIR_FILTER: SensorEntityDescription(
|
||||
key=ThinQProperty.FRESH_AIR_FILTER,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.FRESH_AIR_FILTER,
|
||||
),
|
||||
}
|
||||
RUN_STATE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.CURRENT_STATE: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_STATE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.CURRENT_STATE,
|
||||
),
|
||||
ThinQProperty.COCK_STATE: SensorEntityDescription(
|
||||
key=ThinQProperty.COCK_STATE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.COCK_STATE,
|
||||
),
|
||||
ThinQProperty.STERILIZING_STATE: SensorEntityDescription(
|
||||
key=ThinQProperty.STERILIZING_STATE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.STERILIZING_STATE,
|
||||
),
|
||||
ThinQProperty.GROWTH_MODE: SensorEntityDescription(
|
||||
key=ThinQProperty.GROWTH_MODE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.GROWTH_MODE,
|
||||
),
|
||||
ThinQProperty.WIND_VOLUME: SensorEntityDescription(
|
||||
key=ThinQProperty.WIND_VOLUME,
|
||||
device_class=SensorDeviceClass.WIND_SPEED,
|
||||
translation_key=ThinQProperty.WIND_VOLUME,
|
||||
),
|
||||
}
|
||||
TEMPERATURE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.TARGET_TEMPERATURE: SensorEntityDescription(
|
||||
key=ThinQProperty.TARGET_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
translation_key=ThinQProperty.TARGET_TEMPERATURE,
|
||||
),
|
||||
ThinQProperty.DAY_TARGET_TEMPERATURE: SensorEntityDescription(
|
||||
key=ThinQProperty.DAY_TARGET_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key=ThinQProperty.DAY_TARGET_TEMPERATURE,
|
||||
),
|
||||
ThinQProperty.NIGHT_TARGET_TEMPERATURE: SensorEntityDescription(
|
||||
key=ThinQProperty.NIGHT_TARGET_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key=ThinQProperty.NIGHT_TARGET_TEMPERATURE,
|
||||
),
|
||||
ThinQProperty.TEMPERATURE_STATE: SensorEntityDescription(
|
||||
key=ThinQProperty.TEMPERATURE_STATE,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
translation_key=ThinQProperty.TEMPERATURE_STATE,
|
||||
),
|
||||
ThinQProperty.CURRENT_TEMPERATURE: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key=ThinQProperty.CURRENT_TEMPERATURE,
|
||||
),
|
||||
}
|
||||
WATER_FILTER_INFO_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.USED_TIME: SensorEntityDescription(
|
||||
key=ThinQProperty.USED_TIME,
|
||||
native_unit_of_measurement=UnitOfTime.MONTHS,
|
||||
translation_key=ThinQProperty.USED_TIME,
|
||||
),
|
||||
}
|
||||
WATER_INFO_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.WATER_TYPE: SensorEntityDescription(
|
||||
key=ThinQProperty.WATER_TYPE,
|
||||
translation_key=ThinQProperty.WATER_TYPE,
|
||||
),
|
||||
}
|
||||
TIMER_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
TimerProperty.RELATIVE_TO_START: SensorEntityDescription(
|
||||
key=TimerProperty.RELATIVE_TO_START,
|
||||
translation_key=TimerProperty.RELATIVE_TO_START,
|
||||
),
|
||||
TimerProperty.RELATIVE_TO_START_WM: SensorEntityDescription(
|
||||
key=TimerProperty.RELATIVE_TO_START,
|
||||
translation_key=TimerProperty.RELATIVE_TO_START_WM,
|
||||
),
|
||||
TimerProperty.RELATIVE_TO_STOP: SensorEntityDescription(
|
||||
key=TimerProperty.RELATIVE_TO_STOP,
|
||||
translation_key=TimerProperty.RELATIVE_TO_STOP,
|
||||
),
|
||||
TimerProperty.RELATIVE_TO_STOP_WM: SensorEntityDescription(
|
||||
key=TimerProperty.RELATIVE_TO_STOP,
|
||||
translation_key=TimerProperty.RELATIVE_TO_STOP_WM,
|
||||
),
|
||||
TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP: SensorEntityDescription(
|
||||
key=TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP,
|
||||
translation_key=TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP,
|
||||
),
|
||||
TimerProperty.ABSOLUTE_TO_START: SensorEntityDescription(
|
||||
key=TimerProperty.ABSOLUTE_TO_START,
|
||||
translation_key=TimerProperty.ABSOLUTE_TO_START,
|
||||
),
|
||||
TimerProperty.ABSOLUTE_TO_STOP: SensorEntityDescription(
|
||||
key=TimerProperty.ABSOLUTE_TO_STOP,
|
||||
translation_key=TimerProperty.ABSOLUTE_TO_STOP,
|
||||
),
|
||||
TimerProperty.REMAIN: SensorEntityDescription(
|
||||
key=TimerProperty.REMAIN,
|
||||
translation_key=TimerProperty.REMAIN,
|
||||
),
|
||||
TimerProperty.TARGET: SensorEntityDescription(
|
||||
key=TimerProperty.TARGET,
|
||||
translation_key=TimerProperty.TARGET,
|
||||
),
|
||||
TimerProperty.RUNNING: SensorEntityDescription(
|
||||
key=TimerProperty.RUNNING,
|
||||
translation_key=TimerProperty.RUNNING,
|
||||
),
|
||||
TimerProperty.TOTAL: SensorEntityDescription(
|
||||
key=TimerProperty.TOTAL,
|
||||
translation_key=TimerProperty.TOTAL,
|
||||
),
|
||||
TimerProperty.LIGHT_START: SensorEntityDescription(
|
||||
key=TimerProperty.LIGHT_START,
|
||||
translation_key=TimerProperty.LIGHT_START,
|
||||
),
|
||||
ThinQProperty.ELAPSED_DAY_STATE: SensorEntityDescription(
|
||||
key=ThinQProperty.ELAPSED_DAY_STATE,
|
||||
native_unit_of_measurement=UnitOfTime.DAYS,
|
||||
translation_key=ThinQProperty.ELAPSED_DAY_STATE,
|
||||
),
|
||||
ThinQProperty.ELAPSED_DAY_TOTAL: SensorEntityDescription(
|
||||
key=ThinQProperty.ELAPSED_DAY_TOTAL,
|
||||
native_unit_of_measurement=UnitOfTime.DAYS,
|
||||
translation_key=ThinQProperty.ELAPSED_DAY_TOTAL,
|
||||
),
|
||||
}
|
||||
|
||||
WASHER_SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RELATIVE_TO_START_WM],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RELATIVE_TO_STOP_WM],
|
||||
TIMER_SENSOR_DESC[TimerProperty.REMAIN],
|
||||
TIMER_SENSOR_DESC[TimerProperty.TOTAL],
|
||||
)
|
||||
DEVICE_TYPE_SENSOR_MAP: dict[DeviceType, tuple[SensorEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM1],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM2],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM10],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.HUMIDITY],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.ODOR_LEVEL],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TOTAL_POLLUTION_LEVEL],
|
||||
FILTER_INFO_SENSOR_DESC[ThinQProperty.FILTER_LIFETIME],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RELATIVE_TO_START],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RELATIVE_TO_STOP],
|
||||
TIMER_SENSOR_DESC[TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP],
|
||||
),
|
||||
DeviceType.AIR_PURIFIER_FAN: (
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM1],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM2],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM10],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.HUMIDITY],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TEMPERATURE],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.MONITORING_ENABLED],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.ODOR_LEVEL],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TOTAL_POLLUTION_LEVEL],
|
||||
TIMER_SENSOR_DESC[TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP],
|
||||
),
|
||||
DeviceType.AIR_PURIFIER: (
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM1],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM2],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM10],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.HUMIDITY],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.MONITORING_ENABLED],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.ODOR_LEVEL],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TOTAL_POLLUTION_LEVEL],
|
||||
JOB_MODE_SENSOR_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
JOB_MODE_SENSOR_DESC[ThinQProperty.PERSONALIZATION_MODE],
|
||||
),
|
||||
DeviceType.COOKTOP: (
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
POWER_SENSOR_DESC[ThinQProperty.POWER_LEVEL],
|
||||
TIMER_SENSOR_DESC[TimerProperty.REMAIN],
|
||||
),
|
||||
DeviceType.DEHUMIDIFIER: (
|
||||
JOB_MODE_SENSOR_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
HUMIDITY_SENSOR_DESC[ThinQProperty.CURRENT_HUMIDITY],
|
||||
),
|
||||
DeviceType.DISH_WASHER: (
|
||||
DISH_WASHING_COURSE_SENSOR_DESC[ThinQProperty.CURRENT_DISH_WASHING_COURSE],
|
||||
PREFERENCE_SENSOR_DESC[ThinQProperty.RINSE_LEVEL],
|
||||
PREFERENCE_SENSOR_DESC[ThinQProperty.SOFTENING_LEVEL],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RELATIVE_TO_START_WM],
|
||||
TIMER_SENSOR_DESC[TimerProperty.REMAIN],
|
||||
TIMER_SENSOR_DESC[TimerProperty.TOTAL],
|
||||
),
|
||||
DeviceType.DRYER: WASHER_SENSORS,
|
||||
DeviceType.HOME_BREW: (
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.RECIPE_NAME],
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.WORT_INFO],
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.YEAST_INFO],
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.HOP_OIL_INFO],
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.FLAVOR_INFO],
|
||||
RECIPE_SENSOR_DESC[ThinQProperty.BEER_REMAIN],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
TIMER_SENSOR_DESC[ThinQProperty.ELAPSED_DAY_STATE],
|
||||
TIMER_SENSOR_DESC[ThinQProperty.ELAPSED_DAY_TOTAL],
|
||||
),
|
||||
DeviceType.HOOD: (TIMER_SENSOR_DESC[TimerProperty.REMAIN],),
|
||||
DeviceType.HUMIDIFIER: (
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM1],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM2],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.PM10],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.HUMIDITY],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TEMPERATURE],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.MONITORING_ENABLED],
|
||||
AIR_QUALITY_SENSOR_DESC[ThinQProperty.TOTAL_POLLUTION_LEVEL],
|
||||
TIMER_SENSOR_DESC[TimerProperty.ABSOLUTE_TO_START],
|
||||
TIMER_SENSOR_DESC[TimerProperty.ABSOLUTE_TO_STOP],
|
||||
TIMER_SENSOR_DESC[TimerProperty.SLEEP_TIMER_RELATIVE_TO_STOP],
|
||||
),
|
||||
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],
|
||||
TIMER_SENSOR_DESC[TimerProperty.REMAIN],
|
||||
),
|
||||
DeviceType.OVEN: (
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
TEMPERATURE_SENSOR_DESC[ThinQProperty.TARGET_TEMPERATURE],
|
||||
TIMER_SENSOR_DESC[TimerProperty.REMAIN],
|
||||
TIMER_SENSOR_DESC[TimerProperty.TARGET],
|
||||
),
|
||||
DeviceType.PLANT_CULTIVATOR: (
|
||||
LIGHT_SENSOR_DESC[ThinQProperty.BRIGHTNESS],
|
||||
LIGHT_SENSOR_DESC[ThinQProperty.DURATION],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.GROWTH_MODE],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.WIND_VOLUME],
|
||||
TEMPERATURE_SENSOR_DESC[ThinQProperty.DAY_TARGET_TEMPERATURE],
|
||||
TEMPERATURE_SENSOR_DESC[ThinQProperty.NIGHT_TARGET_TEMPERATURE],
|
||||
TEMPERATURE_SENSOR_DESC[ThinQProperty.TEMPERATURE_STATE],
|
||||
TIMER_SENSOR_DESC[TimerProperty.LIGHT_START],
|
||||
),
|
||||
DeviceType.REFRIGERATOR: (
|
||||
REFRIGERATION_SENSOR_DESC[ThinQProperty.FRESH_AIR_FILTER],
|
||||
WATER_FILTER_INFO_SENSOR_DESC[ThinQProperty.USED_TIME],
|
||||
),
|
||||
DeviceType.ROBOT_CLEANER: (
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
JOB_MODE_SENSOR_DESC[ThinQProperty.CURRENT_JOB_MODE],
|
||||
TIMER_SENSOR_DESC[TimerProperty.RUNNING],
|
||||
),
|
||||
DeviceType.STICK_CLEANER: (
|
||||
BATTERY_SENSOR_DESC[ThinQProperty.BATTERY_PERCENT],
|
||||
JOB_MODE_SENSOR_DESC[ThinQPropertyEx.CURRENT_JOB_MODE_STICK_CLEANER],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.CURRENT_STATE],
|
||||
),
|
||||
DeviceType.STYLER: WASHER_SENSORS,
|
||||
DeviceType.WASHCOMBO_MAIN: WASHER_SENSORS,
|
||||
DeviceType.WASHCOMBO_MINI: WASHER_SENSORS,
|
||||
DeviceType.WASHER: WASHER_SENSORS,
|
||||
DeviceType.WASHTOWER_DRYER: WASHER_SENSORS,
|
||||
DeviceType.WASHTOWER: WASHER_SENSORS,
|
||||
DeviceType.WASHTOWER_WASHER: WASHER_SENSORS,
|
||||
DeviceType.WATER_HEATER: (
|
||||
TEMPERATURE_SENSOR_DESC[ThinQProperty.CURRENT_TEMPERATURE],
|
||||
),
|
||||
DeviceType.WATER_PURIFIER: (
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.COCK_STATE],
|
||||
RUN_STATE_SENSOR_DESC[ThinQProperty.STERILIZING_STATE],
|
||||
WATER_INFO_SENSOR_DESC[ThinQProperty.WATER_TYPE],
|
||||
),
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for sensor platform."""
|
||||
entities: list[ThinQSensorEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_SENSOR_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQSensorEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(
|
||||
description.key,
|
||||
(
|
||||
ActiveMode.READABLE
|
||||
if coordinator.api.device.device_type == DeviceType.COOKTOP
|
||||
else ActiveMode.READ_ONLY
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQSensorEntity(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 entity_description.device_class == SensorDeviceClass.ENUM:
|
||||
self._attr_options = self.data.options
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
self._attr_native_value = self.data.value
|
||||
|
||||
if (data_unit := self._get_unit_of_measurement(self.data.unit)) is not None:
|
||||
# For different from description's unit
|
||||
self._attr_native_unit_of_measurement = data_unit
|
||||
|
||||
_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,
|
||||
)
|
|
@ -20,8 +20,44 @@
|
|||
},
|
||||
"entity": {
|
||||
"switch": {
|
||||
"auto_mode": {
|
||||
"name": "Auto mode"
|
||||
},
|
||||
"express_mode": {
|
||||
"name": "Ice plus"
|
||||
},
|
||||
"hot_water_mode": {
|
||||
"name": "Hot water"
|
||||
},
|
||||
"humidity_warm_mode": {
|
||||
"name": "Warm mist"
|
||||
},
|
||||
"hygiene_dry_mode": {
|
||||
"name": "Drying mode"
|
||||
},
|
||||
"mood_lamp_state": {
|
||||
"name": "Mood light"
|
||||
},
|
||||
"operation_power": {
|
||||
"name": "Power"
|
||||
"name": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::high%]"
|
||||
},
|
||||
"optimal_humidity": {
|
||||
"name": "Ventilation"
|
||||
},
|
||||
"power_save_enabled": {
|
||||
"name": "Energy saving"
|
||||
},
|
||||
"rapid_freeze": {
|
||||
"name": "Quick freeze"
|
||||
},
|
||||
"sleep_mode": {
|
||||
"name": "Sleep mode"
|
||||
},
|
||||
"uv_nano": {
|
||||
"name": "UVnano"
|
||||
},
|
||||
"warm_mode": {
|
||||
"name": "Heating"
|
||||
}
|
||||
},
|
||||
"binary_sensor": {
|
||||
|
@ -58,6 +94,896 @@
|
|||
"one_touch_filter": {
|
||||
"name": "Fresh air filter"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"climate_air_conditioner": {
|
||||
"state_attributes": {
|
||||
"fan_mode": {
|
||||
"state": {
|
||||
"slow": "Slow",
|
||||
"low": "Low",
|
||||
"mid": "Medium",
|
||||
"high": "High",
|
||||
"power": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::high%]",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]"
|
||||
}
|
||||
},
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"air_clean": "Air purify",
|
||||
"aroma": "Aroma",
|
||||
"energy_saving": "Energy saving"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"event": {
|
||||
"error": {
|
||||
"name": "Error",
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
"state": {
|
||||
"block_error": "Cleaning has stopped. Check for obstacles",
|
||||
"brush_error": "Moving brush has a problem",
|
||||
"bubble_error": "Bubble error",
|
||||
"child_lock_active_error": "Child lock",
|
||||
"cliff_error": "Fall prevention sensor has an error",
|
||||
"clutch_error": "Clutch error",
|
||||
"compressor_error": "Compressor error",
|
||||
"dispensing_error": "Dispensor error",
|
||||
"door_close_error": "Door closed error",
|
||||
"door_lock_error": "Door lock error",
|
||||
"door_open_error": "Door open",
|
||||
"door_sensor_error": "Door sensor error",
|
||||
"drainmotor_error": "Drain error",
|
||||
"dust_full_error": "Dust bin is full and needs to be emptied",
|
||||
"empty_water_alert_error": "Empty water",
|
||||
"fan_motor_error": "Fan lock error",
|
||||
"filter_clogging_error": "Filter error",
|
||||
"frozen_error": "Freezing detection error",
|
||||
"heater_circuit_error": "Heater circuit failure",
|
||||
"high_power_supply_error": "Power supply error",
|
||||
"high_temperature_detection_error": "High-temperature error",
|
||||
"inner_lid_open_error": "Lid open error",
|
||||
"ir_sensor_error": "IR sensor error",
|
||||
"le_error": "LE error",
|
||||
"le2_error": "LE2 error",
|
||||
"left_wheel_error": "Left wheel has a problem",
|
||||
"locked_motor_error": "Driver motor error",
|
||||
"mop_error": "Cannot operate properly without the mop attached",
|
||||
"motor_error": "Motor trouble",
|
||||
"motor_lock_error": "Motor lock error",
|
||||
"move_error": "The wheels are not touching the floor",
|
||||
"need_water_drain": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::empty_water_alert_error%]",
|
||||
"need_water_replenishment": "Fill water",
|
||||
"no_battery_error": "Robot cleaner's battery is low",
|
||||
"no_dust_bin_error": "Dust bin is not installed",
|
||||
"no_filter_error": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::filter_clogging_error%]",
|
||||
"out_of_balance_error": "Out of balance load",
|
||||
"overfill_error": "Overfill error",
|
||||
"part_malfunction_error": "AIE error",
|
||||
"power_code_connection_error": "Power cord connection error",
|
||||
"power_fail_error": "Power failure",
|
||||
"right_wheel_error": "Right wheel has a problem",
|
||||
"stack_error": "Stacking error",
|
||||
"steam_heat_error": "Steam heater error",
|
||||
"suction_blocked_error": "Suction motor is clogged",
|
||||
"temperature_sensor_error": "Thermistor error",
|
||||
"time_to_run_the_tub_clean_cycle_error": "Tub clean recommendation",
|
||||
"timeout_error": "Timeout error",
|
||||
"turbidity_sensor_error": "turbidity sensor error",
|
||||
"unable_to_lock_error": "Door lock error",
|
||||
"unbalanced_load_error": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::out_of_balance_error%]",
|
||||
"unknown_error": "Product requires attention",
|
||||
"vibration_sensor_error": "Vibration sensor error",
|
||||
"water_drain_error": "Water drain error",
|
||||
"water_leakage_error": "Water leakage problem",
|
||||
"water_leaks_error": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::water_leakage_error%]",
|
||||
"water_level_sensor_error": "Water sensor error",
|
||||
"water_supply_error": "Water supply error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"name": "Notification",
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
"state": {
|
||||
"charging_is_complete": "Charging is completed",
|
||||
"cleaning_is_complete": "Cycle is finished",
|
||||
"cleaning_is_completed": "Cleaning is completed",
|
||||
"cleaning_is_failed": "Cleaning has failed",
|
||||
"cooking_is_complete": "Turned off",
|
||||
"door_is_open": "The door is open",
|
||||
"drying_failed": "An error has occurred in the dryer",
|
||||
"drying_is_complete": "Drying is completed",
|
||||
"error_during_cleaning": "Cleaning stopped due to an error",
|
||||
"error_during_washing": "An error has occurred in the washing machine",
|
||||
"error_has_occurred": "An error has occurred",
|
||||
"frozen_is_complete": "Ice plus is done",
|
||||
"homeguard_is_stopped": "Home guard has stopped",
|
||||
"lack_of_water": "There is no water in the water tank",
|
||||
"motion_is_detected": "Photograph is sent as movement is detected during home guard",
|
||||
"need_to_check_location": "Location check is required",
|
||||
"pollution_is_high": "Air status is rapidly becoming bad",
|
||||
"preheating_is_complete": "Preheating is done",
|
||||
"rinse_is_not_enough": "Add rinse aid for better drying performance",
|
||||
"salt_refill_is_needed": "Add salt for better softening performance",
|
||||
"scheduled_cleaning_starts": "Scheduled cleaning starts",
|
||||
"styling_is_complete": "Styling is completed",
|
||||
"time_to_change_filter": "It is time to replace the filter",
|
||||
"time_to_change_water_filter": "You need to replace water filter",
|
||||
"time_to_clean": "Need to selfcleaning",
|
||||
"time_to_clean_filter": "It is time to clean the filter",
|
||||
"timer_is_complete": "Timer has been completed",
|
||||
"washing_is_complete": "Washing is completed",
|
||||
"water_is_full": "Water is full",
|
||||
"water_leak_has_occurred": "The dishwasher has detected a water leak"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"target_temperature": {
|
||||
"name": "[%key:component::sensor::entity_component::temperature::name%]"
|
||||
},
|
||||
"target_temperature_for_location": {
|
||||
"name": "{location} temperature"
|
||||
},
|
||||
"light_status": {
|
||||
"name": "Light"
|
||||
},
|
||||
"fan_speed": {
|
||||
"name": "Fan"
|
||||
},
|
||||
"lamp_brightness": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::light_status::name%]"
|
||||
},
|
||||
"wind_temperature": {
|
||||
"name": "Wind temperature"
|
||||
},
|
||||
"relative_hour_to_start": {
|
||||
"name": "Schedule turn-on"
|
||||
},
|
||||
"relative_hour_to_start_for_location": {
|
||||
"name": "{location} schedule turn-on"
|
||||
},
|
||||
"relative_hour_to_start_wm": {
|
||||
"name": "Delay starts in"
|
||||
},
|
||||
"relative_hour_to_start_wm_for_location": {
|
||||
"name": "{location} delay starts in"
|
||||
},
|
||||
"relative_hour_to_stop": {
|
||||
"name": "Schedule turn-off"
|
||||
},
|
||||
"relative_hour_to_stop_for_location": {
|
||||
"name": "{location} schedule turn-off"
|
||||
},
|
||||
"relative_hour_to_stop_wm": {
|
||||
"name": "Delay ends in"
|
||||
},
|
||||
"relative_hour_to_stop_wm_for_location": {
|
||||
"name": "{location} delay ends in"
|
||||
},
|
||||
"sleep_timer_relative_hour_to_stop": {
|
||||
"name": "Sleep timer"
|
||||
},
|
||||
"sleep_timer_relative_hour_to_stop_for_location": {
|
||||
"name": "{location} sleep timer"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"odor_level": {
|
||||
"name": "Odor",
|
||||
"state": {
|
||||
"invalid": "Invalid",
|
||||
"weak": "Weak",
|
||||
"normal": "Normal",
|
||||
"strong": "Strong",
|
||||
"very_strong": "Very strong"
|
||||
}
|
||||
},
|
||||
"current_temperature": {
|
||||
"name": "Current temperature"
|
||||
},
|
||||
"temperature": {
|
||||
"name": "Temperature"
|
||||
},
|
||||
"total_pollution_level": {
|
||||
"name": "Overall air quality",
|
||||
"state": {
|
||||
"invalid": "Invalid",
|
||||
"good": "Good",
|
||||
"normal": "Moderate",
|
||||
"bad": "Unhealthy",
|
||||
"very_bad": "Poor"
|
||||
}
|
||||
},
|
||||
"monitoring_enabled": {
|
||||
"name": "Air quality sensor",
|
||||
"state": {
|
||||
"on_working": "Turns on with product",
|
||||
"always": "Always on"
|
||||
}
|
||||
},
|
||||
"growth_mode": {
|
||||
"name": "Mode",
|
||||
"state": {
|
||||
"standard": "Auto",
|
||||
"ext_leaf": "Vegetables",
|
||||
"ext_herb": "Herbs",
|
||||
"ext_flower": "Flowers",
|
||||
"ext_expert": "Custom growing mode"
|
||||
}
|
||||
},
|
||||
"growth_mode_for_location": {
|
||||
"name": "{location} mode",
|
||||
"state": {
|
||||
"standard": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"ext_leaf": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::ext_leaf%]",
|
||||
"ext_herb": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::ext_herb%]",
|
||||
"ext_flower": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::ext_flower%]",
|
||||
"ext_expert": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::ext_expert%]"
|
||||
}
|
||||
},
|
||||
"wind_volume_for_location": {
|
||||
"name": "{location} wind speed"
|
||||
},
|
||||
"brightness": {
|
||||
"name": "Lighting intensity"
|
||||
},
|
||||
"brightness_for_location": {
|
||||
"name": "{location} lighting intensity"
|
||||
},
|
||||
"duration": {
|
||||
"name": "Lighting duration"
|
||||
},
|
||||
"duration_for_location": {
|
||||
"name": "{location} lighting duration"
|
||||
},
|
||||
"day_target_temperature": {
|
||||
"name": "Day growth temperature"
|
||||
},
|
||||
"day_target_temperature_for_location": {
|
||||
"name": "{location} day growth temperature"
|
||||
},
|
||||
"night_target_temperature": {
|
||||
"name": "Night growth temperature"
|
||||
},
|
||||
"night_target_temperature_for_location": {
|
||||
"name": "{location} night growth temperature"
|
||||
},
|
||||
"temperature_state": {
|
||||
"name": "[%key:component::sensor::entity_component::temperature::name%]",
|
||||
"state": {
|
||||
"high": "High",
|
||||
"normal": "Good",
|
||||
"low": "Low"
|
||||
}
|
||||
},
|
||||
"temperature_state_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::target_temperature_for_location::name%]",
|
||||
"state": {
|
||||
"high": "[%key:component::lg_thinq::entity::sensor::temperature_state::state::high%]",
|
||||
"normal": "[%key:component::lg_thinq::entity::sensor::temperature_state::state::normal%]",
|
||||
"low": "[%key:component::lg_thinq::entity::sensor::temperature_state::state::low%]"
|
||||
}
|
||||
},
|
||||
"current_state": {
|
||||
"name": "Current status",
|
||||
"state": {
|
||||
"add_drain": "Filling",
|
||||
"as_pop_up": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::unknown_error%]",
|
||||
"cancel": "Cancel",
|
||||
"carbonation": "Carbonation",
|
||||
"change_condition": "Settings Change",
|
||||
"charging": "Charging",
|
||||
"charging_complete": "Charging completed",
|
||||
"checking_turbidity": "Detecting soil level",
|
||||
"cleaning": "Cleaning",
|
||||
"cleaning_is_done": "Cleaning is done",
|
||||
"complete": "Done",
|
||||
"cook": "Cooking",
|
||||
"cook_complete": "[%key:component::lg_thinq::entity::sensor::current_state::state::complete%]",
|
||||
"cooking_in_progress": "[%key:component::lg_thinq::entity::sensor::current_state::state::cook%]",
|
||||
"cool_down": "Cool down",
|
||||
"cooling": "Cooling",
|
||||
"detecting": "Detecting",
|
||||
"detergent_amount": "Providing the info about the amount of detergent",
|
||||
"diagnosis": "Smart diagnosis is in progress",
|
||||
"dispensing": "Auto dispensing",
|
||||
"display_loadsize": "Load size",
|
||||
"done": "[%key:component::lg_thinq::entity::sensor::current_state::state::complete%]",
|
||||
"drying": "Drying",
|
||||
"during_aging": "Aging",
|
||||
"during_fermentation": "Fermentation",
|
||||
"end": "Finished",
|
||||
"end_cooling": "[%key:component::lg_thinq::entity::sensor::current_state::state::drying%]",
|
||||
"error": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::unknown_error%]",
|
||||
"extracting_capsule": "Capsule brewing",
|
||||
"extraction_mode": "Storing",
|
||||
"firmware": "Updating firmware",
|
||||
"fota": "Updating",
|
||||
"frozen_prevent_initial": "Freeze protection standby",
|
||||
"frozen_prevent_running": "Freeze protection in progress",
|
||||
"frozen_prevent_pause": "Freeze protection paused",
|
||||
"homing": "Moving",
|
||||
"initial": "[%key:common::state::standby%]",
|
||||
"initializing": "[%key:common::state::standby%]",
|
||||
"lock": "Control lock",
|
||||
"macrosector": "Remote is in use",
|
||||
"melting": "Wort dissolving",
|
||||
"monitoring_detecting": "HomeGuard is active",
|
||||
"monitoring_moving": "Going to the starting point",
|
||||
"monitoring_positioning": "Setting homeguard start point",
|
||||
"night_dry": "Night dry",
|
||||
"oven_setting": "Cooktop connected",
|
||||
"pause": "[%key:common::state::paused%]",
|
||||
"paused": "[%key:common::state::paused%]",
|
||||
"power_fail": "Power fail",
|
||||
"power_on": "[%key:common::state::on%]",
|
||||
"power_off": "[%key:common::state::off%]",
|
||||
"preference": "Setting",
|
||||
"preheat": "Preheating",
|
||||
"preheat_complete": "[%key:component::lg_thinq::entity::event::notification::state_attributes::event_type::state::preheating_is_complete%]",
|
||||
"preheating": "[%key:component::lg_thinq::entity::sensor::current_state::state::preheat%]",
|
||||
"preheating_is_done": "[%key:component::lg_thinq::entity::event::notification::state_attributes::event_type::state::preheating_is_complete%]",
|
||||
"prepareing_fermentation": "Preparing now",
|
||||
"presteam": "Ready to steam",
|
||||
"prewash": "Prewashing",
|
||||
"proofing": "Proofing",
|
||||
"refreshing": "Refreshing",
|
||||
"reservation": "[%key:component::lg_thinq::entity::sensor::current_state::state::macrosector%]",
|
||||
"reserved": "Delay set",
|
||||
"rinse_hold": "Waiting to rinse",
|
||||
"rinsing": "Rinsing",
|
||||
"running": "Running",
|
||||
"running_end": "Complete",
|
||||
"setdate": "[%key:component::lg_thinq::entity::sensor::current_state::state::macrosector%]",
|
||||
"shoes_module": "Drying shoes",
|
||||
"sleep": "In sleep mode",
|
||||
"smart_grid_run": "Running smart grid",
|
||||
"soaking": "Soak",
|
||||
"softening": "Softener",
|
||||
"spinning": "Spinning",
|
||||
"stay": "Refresh",
|
||||
"standby": "[%key:common::state::standby%]",
|
||||
"steam": "Refresh",
|
||||
"steam_softening": "Steam softening",
|
||||
"sterilize": "Sterilize",
|
||||
"temperature_stabilization": "Temperature adjusting",
|
||||
"working": "[%key:component::lg_thinq::entity::sensor::current_state::state::cleaning%]",
|
||||
"wrinkle_care": "Wrinkle care"
|
||||
}
|
||||
},
|
||||
"current_state_for_location": {
|
||||
"name": "{location} current status",
|
||||
"state": {
|
||||
"add_drain": "[%key:component::lg_thinq::entity::sensor::current_state::state::add_drain%]",
|
||||
"as_pop_up": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::unknown_error%]",
|
||||
"cancel": "[%key:component::lg_thinq::entity::sensor::current_state::state::cancel%]",
|
||||
"carbonation": "[%key:component::lg_thinq::entity::sensor::current_state::state::carbonation%]",
|
||||
"change_condition": "[%key:component::lg_thinq::entity::sensor::current_state::state::change_condition%]",
|
||||
"charging": "[%key:component::lg_thinq::entity::sensor::current_state::state::charging%]",
|
||||
"charging_complete": "[%key:component::lg_thinq::entity::sensor::current_state::state::charging_complete%]",
|
||||
"checking_turbidity": "[%key:component::lg_thinq::entity::sensor::current_state::state::checking_turbidity%]",
|
||||
"cleaning": "[%key:component::lg_thinq::entity::sensor::current_state::state::cleaning%]",
|
||||
"cleaning_is_done": "[%key:component::lg_thinq::entity::sensor::current_state::state::cleaning_is_done%]",
|
||||
"complete": "[%key:component::lg_thinq::entity::sensor::current_state::state::complete%]",
|
||||
"cook": "[%key:component::lg_thinq::entity::sensor::current_state::state::cook%]",
|
||||
"cook_complete": "[%key:component::lg_thinq::entity::sensor::current_state::state::complete%]",
|
||||
"cooking_in_progress": "[%key:component::lg_thinq::entity::sensor::current_state::state::cook%]",
|
||||
"cool_down": "[%key:component::lg_thinq::entity::sensor::current_state::state::cool_down%]",
|
||||
"cooling": "[%key:component::lg_thinq::entity::sensor::current_state::state::cooling%]",
|
||||
"detecting": "[%key:component::lg_thinq::entity::sensor::current_state::state::detecting%]",
|
||||
"detergent_amount": "[%key:component::lg_thinq::entity::sensor::current_state::state::detergent_amount%]",
|
||||
"diagnosis": "[%key:component::lg_thinq::entity::sensor::current_state::state::diagnosis%]",
|
||||
"dispensing": "[%key:component::lg_thinq::entity::sensor::current_state::state::dispensing%]",
|
||||
"display_loadsize": "[%key:component::lg_thinq::entity::sensor::current_state::state::display_loadsize%]",
|
||||
"done": "[%key:component::lg_thinq::entity::sensor::current_state::state::complete%]",
|
||||
"drying": "[%key:component::lg_thinq::entity::sensor::current_state::state::drying%]",
|
||||
"during_aging": "[%key:component::lg_thinq::entity::sensor::current_state::state::during_aging%]",
|
||||
"during_fermentation": "[%key:component::lg_thinq::entity::sensor::current_state::state::during_fermentation%]",
|
||||
"end": "[%key:component::lg_thinq::entity::sensor::current_state::state::end%]",
|
||||
"end_cooling": "[%key:component::lg_thinq::entity::sensor::current_state::state::drying%]",
|
||||
"error": "[%key:component::lg_thinq::entity::event::error::state_attributes::event_type::state::unknown_error%]",
|
||||
"extracting_capsule": "[%key:component::lg_thinq::entity::sensor::current_state::state::extracting_capsule%]",
|
||||
"extraction_mode": "[%key:component::lg_thinq::entity::sensor::current_state::state::extraction_mode%]",
|
||||
"firmware": "[%key:component::lg_thinq::entity::sensor::current_state::state::firmware%]",
|
||||
"fota": "[%key:component::lg_thinq::entity::sensor::current_state::state::fota%]",
|
||||
"frozen_prevent_initial": "[%key:component::lg_thinq::entity::sensor::current_state::state::frozen_prevent_initial%]",
|
||||
"frozen_prevent_running": "[%key:component::lg_thinq::entity::sensor::current_state::state::frozen_prevent_running%]",
|
||||
"frozen_prevent_pause": "[%key:component::lg_thinq::entity::sensor::current_state::state::frozen_prevent_pause%]",
|
||||
"homing": "[%key:component::lg_thinq::entity::sensor::current_state::state::homing%]",
|
||||
"initial": "[%key:common::state::standby%]",
|
||||
"initializing": "[%key:common::state::standby%]",
|
||||
"lock": "[%key:component::lg_thinq::entity::sensor::current_state::state::lock%]",
|
||||
"macrosector": "[%key:component::lg_thinq::entity::sensor::current_state::state::macrosector%]",
|
||||
"melting": "[%key:component::lg_thinq::entity::sensor::current_state::state::melting%]",
|
||||
"monitoring_detecting": "[%key:component::lg_thinq::entity::sensor::current_state::state::monitoring_detecting%]",
|
||||
"monitoring_moving": "[%key:component::lg_thinq::entity::sensor::current_state::state::monitoring_moving%]",
|
||||
"monitoring_positioning": "[%key:component::lg_thinq::entity::sensor::current_state::state::monitoring_positioning%]",
|
||||
"night_dry": "[%key:component::lg_thinq::entity::sensor::current_state::state::night_dry%]",
|
||||
"oven_setting": "[%key:component::lg_thinq::entity::sensor::current_state::state::oven_setting%]",
|
||||
"pause": "[%key:common::state::paused%]",
|
||||
"paused": "[%key:common::state::paused%]",
|
||||
"power_fail": "[%key:component::lg_thinq::entity::sensor::current_state::state::power_fail%]",
|
||||
"power_on": "[%key:common::state::on%]",
|
||||
"power_off": "[%key:common::state::off%]",
|
||||
"preference": "[%key:component::lg_thinq::entity::sensor::current_state::state::preference%]",
|
||||
"preheat": "[%key:component::lg_thinq::entity::sensor::current_state::state::preheat%]",
|
||||
"preheat_complete": "[%key:component::lg_thinq::entity::event::notification::state_attributes::event_type::state::preheating_is_complete%]",
|
||||
"preheating": "[%key:component::lg_thinq::entity::sensor::current_state::state::preheat%]",
|
||||
"preheating_is_done": "[%key:component::lg_thinq::entity::event::notification::state_attributes::event_type::state::preheating_is_complete%]",
|
||||
"prepareing_fermentation": "[%key:component::lg_thinq::entity::sensor::current_state::state::prepareing_fermentation%]",
|
||||
"presteam": "[%key:component::lg_thinq::entity::sensor::current_state::state::presteam%]",
|
||||
"prewash": "[%key:component::lg_thinq::entity::sensor::current_state::state::prewash%]",
|
||||
"proofing": "[%key:component::lg_thinq::entity::sensor::current_state::state::proofing%]",
|
||||
"refreshing": "[%key:component::lg_thinq::entity::sensor::current_state::state::refreshing%]",
|
||||
"reservation": "[%key:component::lg_thinq::entity::sensor::current_state::state::macrosector%]",
|
||||
"reserved": "[%key:component::lg_thinq::entity::sensor::current_state::state::reserved%]",
|
||||
"rinse_hold": "[%key:component::lg_thinq::entity::sensor::current_state::state::rinse_hold%]",
|
||||
"rinsing": "[%key:component::lg_thinq::entity::sensor::current_state::state::rinsing%]",
|
||||
"running": "[%key:component::lg_thinq::entity::sensor::current_state::state::running%]",
|
||||
"running_end": "[%key:component::lg_thinq::entity::sensor::current_state::state::running_end%]",
|
||||
"setdate": "[%key:component::lg_thinq::entity::sensor::current_state::state::macrosector%]",
|
||||
"shoes_module": "[%key:component::lg_thinq::entity::sensor::current_state::state::shoes_module%]",
|
||||
"sleep": "[%key:component::lg_thinq::entity::sensor::current_state::state::sleep%]",
|
||||
"smart_grid_run": "[%key:component::lg_thinq::entity::sensor::current_state::state::smart_grid_run%]",
|
||||
"soaking": "[%key:component::lg_thinq::entity::sensor::current_state::state::soaking%]",
|
||||
"softening": "[%key:component::lg_thinq::entity::sensor::current_state::state::softening%]",
|
||||
"spinning": "[%key:component::lg_thinq::entity::sensor::current_state::state::spinning%]",
|
||||
"stay": "[%key:component::lg_thinq::entity::sensor::current_state::state::stay%]",
|
||||
"standby": "[%key:common::state::standby%]",
|
||||
"steam": "[%key:component::lg_thinq::entity::sensor::current_state::state::steam%]",
|
||||
"steam_softening": "[%key:component::lg_thinq::entity::sensor::current_state::state::steam_softening%]",
|
||||
"sterilize": "[%key:component::lg_thinq::entity::sensor::current_state::state::sterilize%]",
|
||||
"temperature_stabilization": "[%key:component::lg_thinq::entity::sensor::current_state::state::temperature_stabilization%]",
|
||||
"working": "[%key:component::lg_thinq::entity::sensor::current_state::state::cleaning%]",
|
||||
"wrinkle_care": "[%key:component::lg_thinq::entity::sensor::current_state::state::wrinkle_care%]"
|
||||
}
|
||||
},
|
||||
"fresh_air_filter": {
|
||||
"name": "[%key:component::lg_thinq::entity::binary_sensor::one_touch_filter::name%]",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"power": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::high%]",
|
||||
"replace": "Replace filter",
|
||||
"smart_power": "Smart safe storage",
|
||||
"smart_off": "[%key:common::state::off%]",
|
||||
"smart_on": "[%key:component::lg_thinq::entity::sensor::fresh_air_filter::state::smart_power%]"
|
||||
}
|
||||
},
|
||||
"filter_lifetime": {
|
||||
"name": "Filter remaining"
|
||||
},
|
||||
"used_time": {
|
||||
"name": "Water filter used"
|
||||
},
|
||||
"current_job_mode": {
|
||||
"name": "Operating mode",
|
||||
"state": {
|
||||
"air_clean": "Purify",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"clothes_dry": "Laundry",
|
||||
"edge": "Edge cleaning",
|
||||
"heat_pump": "Heat pump",
|
||||
"high": "Power",
|
||||
"intensive_dry": "Spot",
|
||||
"macro": "Custom mode",
|
||||
"mop": "Mop",
|
||||
"normal": "Normal",
|
||||
"off": "[%key:common::state::off%]",
|
||||
"quiet_humidity": "Silent",
|
||||
"rapid_humidity": "Jet",
|
||||
"sector_base": "Cell by cell",
|
||||
"select": "My space",
|
||||
"smart_humidity": "Smart",
|
||||
"spot": "Spiral spot mode",
|
||||
"turbo": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]",
|
||||
"vacation": "Vacation",
|
||||
"zigzag": "Zigzag"
|
||||
}
|
||||
},
|
||||
"current_job_mode_stick_cleaner": {
|
||||
"name": "Operating mode",
|
||||
"state": {
|
||||
"auto": "Low power",
|
||||
"high": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::high%]",
|
||||
"mop": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::mop%]",
|
||||
"normal": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::normal%]",
|
||||
"off": "[%key:common::state::off%]",
|
||||
"turbo": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]"
|
||||
}
|
||||
},
|
||||
"personalization_mode": {
|
||||
"name": "Personal mode",
|
||||
"state": {
|
||||
"auto_inside": "[%key:component::lg_thinq::entity::switch::auto_mode::name%]",
|
||||
"sleep": "Sleep mode",
|
||||
"baby": "Baby care mode",
|
||||
"sick_house": "New Home mode",
|
||||
"auto_outside": "Interlocking mode",
|
||||
"pet": "Pet mode",
|
||||
"cooking": "Cooking mode",
|
||||
"smoke": "Smoke mode",
|
||||
"exercise": "Exercise mode",
|
||||
"others": "Others"
|
||||
}
|
||||
},
|
||||
"current_dish_washing_course": {
|
||||
"name": "Current cycle",
|
||||
"state": {
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"heavy": "Intensive",
|
||||
"delicate": "Delicate",
|
||||
"turbo": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]",
|
||||
"normal": "Normal",
|
||||
"rinse": "Rinse",
|
||||
"refresh": "Refresh",
|
||||
"express": "Express",
|
||||
"machine_clean": "Machine clean",
|
||||
"short_mode": "Short mode",
|
||||
"download_cycle": "Download cycle",
|
||||
"quick": "Quick",
|
||||
"steam": "Steam care",
|
||||
"spray": "Spray",
|
||||
"eco": "Eco"
|
||||
}
|
||||
},
|
||||
"rinse_level": {
|
||||
"name": "Rinse aid dispenser level",
|
||||
"state": {
|
||||
"rinselevel_0": "0",
|
||||
"rinselevel_1": "1",
|
||||
"rinselevel_2": "2",
|
||||
"rinselevel_3": "3",
|
||||
"rinselevel_4": "4"
|
||||
}
|
||||
},
|
||||
"softening_level": {
|
||||
"name": "Softening level",
|
||||
"state": {
|
||||
"softeninglevel_0": "[%key:component::lg_thinq::entity::sensor::rinse_level::state::rinselevel_0%]",
|
||||
"softeninglevel_1": "[%key:component::lg_thinq::entity::sensor::rinse_level::state::rinselevel_1%]",
|
||||
"softeninglevel_2": "[%key:component::lg_thinq::entity::sensor::rinse_level::state::rinselevel_2%]",
|
||||
"softeninglevel_3": "[%key:component::lg_thinq::entity::sensor::rinse_level::state::rinselevel_3%]",
|
||||
"softeninglevel_4": "[%key:component::lg_thinq::entity::sensor::rinse_level::state::rinselevel_4%]"
|
||||
}
|
||||
},
|
||||
"cock_state": {
|
||||
"name": "[%key:component::lg_thinq::entity::switch::uv_nano::name%]",
|
||||
"state": {
|
||||
"cleaning": "In progress",
|
||||
"normal": "[%key:common::state::standby%]"
|
||||
}
|
||||
},
|
||||
"sterilizing_state": {
|
||||
"name": "High-temp sterilization",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"on": "Sterilizing",
|
||||
"cancel": "[%key:component::lg_thinq::entity::sensor::current_state::state::cancel%]"
|
||||
}
|
||||
},
|
||||
"water_type": {
|
||||
"name": "Type"
|
||||
},
|
||||
"target_temperature": {
|
||||
"name": "[%key:component::sensor::entity_component::temperature::name%]",
|
||||
"state": {
|
||||
"kimchi": "Kimchi",
|
||||
"off": "[%key:common::state::off%]",
|
||||
"freezer": "Freezer",
|
||||
"fridge": "Fridge",
|
||||
"storage": "Storage",
|
||||
"meat_fish": "Meat/Fish",
|
||||
"rice_grain": "Rice/Grain",
|
||||
"vegetable_fruit": "Vege/Fruit",
|
||||
"temperature_number": "Number"
|
||||
}
|
||||
},
|
||||
"target_temperature_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::target_temperature_for_location::name%]",
|
||||
"state": {
|
||||
"kimchi": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::kimchi%]",
|
||||
"off": "[%key:common::state::off%]",
|
||||
"freezer": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::freezer%]",
|
||||
"fridge": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::fridge%]",
|
||||
"storage": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::storage%]",
|
||||
"meat_fish": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::meat_fish%]",
|
||||
"rice_grain": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::rice_grain%]",
|
||||
"vegetable_fruit": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::vegetable_fruit%]",
|
||||
"temperature_number": "[%key:component::lg_thinq::entity::sensor::target_temperature::state::temperature_number%]"
|
||||
}
|
||||
},
|
||||
"elapsed_day_state": {
|
||||
"name": "Brewing period"
|
||||
},
|
||||
"elapsed_day_total": {
|
||||
"name": "Brewing duration"
|
||||
},
|
||||
"recipe_name": {
|
||||
"name": "Homebrew recipe",
|
||||
"state": {
|
||||
"ipa": "IPA",
|
||||
"pale_ale": "Pale ale",
|
||||
"stout": "Stout",
|
||||
"wheat": "Wheat",
|
||||
"pilsner": "Pilsner",
|
||||
"red_ale": "Red ale",
|
||||
"my_recipe": "My recipe"
|
||||
}
|
||||
},
|
||||
"wort_info": {
|
||||
"name": "Wort",
|
||||
"state": {
|
||||
"hoppy": "Hoppy",
|
||||
"deep_gold": "DeepGold",
|
||||
"wheat": "Wheat",
|
||||
"dark": "Dark"
|
||||
}
|
||||
},
|
||||
"yeast_info": {
|
||||
"name": "Yeast",
|
||||
"state": {
|
||||
"american_ale": "American ale",
|
||||
"english_ale": "English ale",
|
||||
"lager": "Lager",
|
||||
"weizen": "Weizen"
|
||||
}
|
||||
},
|
||||
"hop_oil_info": {
|
||||
"name": "Hops"
|
||||
},
|
||||
"flavor_info": {
|
||||
"name": "Flavor"
|
||||
},
|
||||
"beer_remain": {
|
||||
"name": "Recipe progress"
|
||||
},
|
||||
"battery_level": {
|
||||
"name": "Battery",
|
||||
"state": {
|
||||
"high": "Full",
|
||||
"mid": "Medium",
|
||||
"low": "Low",
|
||||
"warning": "Empty"
|
||||
}
|
||||
},
|
||||
"relative_to_start": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start::name%]"
|
||||
},
|
||||
"relative_to_start_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start_for_location::name%]"
|
||||
},
|
||||
"relative_to_start_wm": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start_wm::name%]"
|
||||
},
|
||||
"relative_to_start_wm_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start_wm_for_location::name%]"
|
||||
},
|
||||
"relative_to_stop": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop::name%]"
|
||||
},
|
||||
"relative_to_stop_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop_for_location::name%]"
|
||||
},
|
||||
"relative_to_stop_wm": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop_wm::name%]"
|
||||
},
|
||||
"relative_to_stop_wm_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop_wm_for_location::name%]"
|
||||
},
|
||||
"sleep_timer_relative_to_stop": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::sleep_timer_relative_hour_to_stop::name%]"
|
||||
},
|
||||
"sleep_timer_relative_to_stop_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::sleep_timer_relative_hour_to_stop_for_location::name%]"
|
||||
},
|
||||
"absolute_to_start": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start::name%]"
|
||||
},
|
||||
"absolute_to_start_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_start_for_location::name%]"
|
||||
},
|
||||
"absolute_to_stop": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop::name%]"
|
||||
},
|
||||
"absolute_to_stop_for_location": {
|
||||
"name": "[%key:component::lg_thinq::entity::number::relative_hour_to_stop_for_location::name%]"
|
||||
},
|
||||
"remain": {
|
||||
"name": "Remaining time"
|
||||
},
|
||||
"remain_for_location": {
|
||||
"name": "{location} remaining time"
|
||||
},
|
||||
"running": {
|
||||
"name": "Running time"
|
||||
},
|
||||
"running_for_location": {
|
||||
"name": "{location} running time"
|
||||
},
|
||||
"total": {
|
||||
"name": "Total time"
|
||||
},
|
||||
"total_for_location": {
|
||||
"name": "{location} total time"
|
||||
},
|
||||
"target": {
|
||||
"name": "Cook time"
|
||||
},
|
||||
"target_for_location": {
|
||||
"name": "{location} cook time"
|
||||
},
|
||||
"light_start": {
|
||||
"name": "Lights on time"
|
||||
},
|
||||
"light_start_for_location": {
|
||||
"name": "{location} lights on time"
|
||||
},
|
||||
"power_level": {
|
||||
"name": "Power level"
|
||||
},
|
||||
"power_level_for_location": {
|
||||
"name": "{location} power level"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"wind_strength": {
|
||||
"name": "Speed",
|
||||
"state": {
|
||||
"slow": "[%key:component::lg_thinq::entity::climate::climate_air_conditioner::state_attributes::fan_mode::state::slow%]",
|
||||
"low": "Low",
|
||||
"mid": "Medium",
|
||||
"high": "High",
|
||||
"power": "Turbo",
|
||||
"turbo": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"wind_1": "Step 1",
|
||||
"wind_2": "Step 2",
|
||||
"wind_3": "Step 3",
|
||||
"wind_4": "Step 4",
|
||||
"wind_5": "Step 5",
|
||||
"wind_6": "Step 6",
|
||||
"wind_7": "Step 7",
|
||||
"wind_8": "Step 8",
|
||||
"wind_9": "Step 9",
|
||||
"wind_10": "Step 10"
|
||||
}
|
||||
},
|
||||
"monitoring_enabled": {
|
||||
"name": "[%key:component::lg_thinq::entity::sensor::monitoring_enabled::name%]",
|
||||
"state": {
|
||||
"on_working": "[%key:component::lg_thinq::entity::sensor::monitoring_enabled::state::on_working%]",
|
||||
"always": "[%key:component::lg_thinq::entity::sensor::monitoring_enabled::state::always%]"
|
||||
}
|
||||
},
|
||||
"current_job_mode": {
|
||||
"name": "Operating mode",
|
||||
"state": {
|
||||
"air_clean": "Purifying",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"baby_care": "[%key:component::lg_thinq::entity::sensor::personalization_mode::state::baby%]",
|
||||
"circulator": "Booster",
|
||||
"clean": "Single",
|
||||
"direct_clean": "Direct mode",
|
||||
"dual_clean": "Dual",
|
||||
"fast": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]",
|
||||
"heat_pump": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::heat_pump%]",
|
||||
"humidify": "Mist",
|
||||
"humidify_and_air_clean": "Mist & purifying",
|
||||
"humidity": "Humid",
|
||||
"nature_clean": "Natural mode",
|
||||
"pet_clean": "[%key:component::lg_thinq::entity::sensor::personalization_mode::state::pet%]",
|
||||
"silent": "Silent",
|
||||
"sleep": "Sleep",
|
||||
"smart": "Smart mode",
|
||||
"space_clean": "Diffusion mode",
|
||||
"spot_clean": "Wide mode",
|
||||
"turbo": "[%key:component::lg_thinq::entity::select::wind_strength::state::power%]",
|
||||
"up_feature": "Additional mode",
|
||||
"vacation": "Vacation"
|
||||
}
|
||||
},
|
||||
"operation_mode": {
|
||||
"name": "Operation",
|
||||
"state": {
|
||||
"cancel": "[%key:component::lg_thinq::entity::sensor::current_state::state::cancel%]",
|
||||
"power_off": "Power off",
|
||||
"preheating": "Preheating",
|
||||
"start": "[%key:common::action::start%]",
|
||||
"stop": "[%key:common::action::stop%]",
|
||||
"wake_up": "Sleep mode off"
|
||||
}
|
||||
},
|
||||
"operation_mode_for_location": {
|
||||
"name": "{location} operation",
|
||||
"state": {
|
||||
"cancel": "[%key:component::lg_thinq::entity::sensor::current_state::state::cancel%]",
|
||||
"power_off": "[%key:component::lg_thinq::entity::select::operation_mode::state::power_off%]",
|
||||
"preheating": "[%key:component::lg_thinq::entity::select::operation_mode::state::preheating%]",
|
||||
"start": "[%key:common::action::start%]",
|
||||
"stop": "[%key:common::action::stop%]",
|
||||
"wake_up": "[%key:component::lg_thinq::entity::select::operation_mode::state::wake_up%]"
|
||||
}
|
||||
},
|
||||
"air_clean_operation_mode": {
|
||||
"name": "[%key:component::lg_thinq::entity::climate::climate_air_conditioner::state_attributes::preset_mode::state::air_clean%]",
|
||||
"state": {
|
||||
"start": "[%key:common::action::start%]",
|
||||
"stop": "[%key:common::action::stop%]"
|
||||
}
|
||||
},
|
||||
"cook_mode": {
|
||||
"name": "Cook mode",
|
||||
"state": {
|
||||
"bake": "Bake",
|
||||
"convection_bake": "Convection bake",
|
||||
"convection_roast": "Convection roast",
|
||||
"roast": "Roast",
|
||||
"crisp_convection": "Crisp convection"
|
||||
}
|
||||
},
|
||||
"cook_mode_for_location": {
|
||||
"name": "{location} cook mode",
|
||||
"state": {
|
||||
"bake": "[%key:component::lg_thinq::entity::select::cook_mode::state::bake%]",
|
||||
"convection_bake": "[%key:component::lg_thinq::entity::select::cook_mode::state::convection_bake%]",
|
||||
"convection_roast": "[%key:component::lg_thinq::entity::select::cook_mode::state::convection_roast%]",
|
||||
"roast": "[%key:component::lg_thinq::entity::select::cook_mode::state::roast%]",
|
||||
"crisp_convection": "[%key:component::lg_thinq::entity::select::cook_mode::state::crisp_convection%]"
|
||||
}
|
||||
},
|
||||
"light_brightness": {
|
||||
"name": "Light"
|
||||
},
|
||||
"wind_angle": {
|
||||
"name": "Rotation",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"angle_45": "45°",
|
||||
"angle_60": "60°",
|
||||
"angle_90": "90°",
|
||||
"angle_140": "140°"
|
||||
}
|
||||
},
|
||||
"display_light": {
|
||||
"name": "Display brightness",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"level_1": "Brightness 1",
|
||||
"level_2": "Brightness 2",
|
||||
"level_3": "Brightness 3"
|
||||
}
|
||||
},
|
||||
"fresh_air_filter": {
|
||||
"name": "[%key:component::lg_thinq::entity::binary_sensor::one_touch_filter::name%]",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"auto": "[%key:component::lg_thinq::entity::sensor::growth_mode::state::standard%]",
|
||||
"power": "[%key:component::lg_thinq::entity::sensor::current_job_mode::state::high%]",
|
||||
"replace": "[%key:component::lg_thinq::entity::sensor::fresh_air_filter::state::replace%]",
|
||||
"smart_power": "[%key:component::lg_thinq::entity::sensor::fresh_air_filter::state::smart_power%]",
|
||||
"smart_off": "[%key:common::state::off%]",
|
||||
"smart_on": "[%key:component::lg_thinq::entity::sensor::fresh_air_filter::state::smart_power%]"
|
||||
}
|
||||
},
|
||||
"hygiene_dry_mode": {
|
||||
"name": "[%key:component::lg_thinq::entity::switch::hygiene_dry_mode::name%]",
|
||||
"state": {
|
||||
"off": "[%key:common::state::off%]",
|
||||
"fast": "Fast",
|
||||
"silent": "Silent",
|
||||
"normal": "[%key:component::lg_thinq::entity::sensor::current_dish_washing_course::state::delicate%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
|
@ -14,39 +15,125 @@ from homeassistant.components.switch import (
|
|||
SwitchEntity,
|
||||
SwitchEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .entity import ThinQEntity
|
||||
|
||||
DEVICE_TYPE_SWITCH_MAP: dict[DeviceType, tuple[SwitchEntityDescription, ...]] = {
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ThinQSwitchEntityDescription(SwitchEntityDescription):
|
||||
"""Describes ThinQ switch entity."""
|
||||
|
||||
on_key: str | None = None
|
||||
off_key: str | None = None
|
||||
|
||||
|
||||
DEVICE_TYPE_SWITCH_MAP: dict[DeviceType, tuple[ThinQSwitchEntityDescription, ...]] = {
|
||||
DeviceType.AIR_CONDITIONER: (
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.POWER_SAVE_ENABLED,
|
||||
translation_key=ThinQProperty.POWER_SAVE_ENABLED,
|
||||
on_key="true",
|
||||
off_key="false",
|
||||
),
|
||||
),
|
||||
DeviceType.AIR_PURIFIER_FAN: (
|
||||
SwitchEntityDescription(
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.AIR_FAN_OPERATION_MODE, translation_key="operation_power"
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.UV_NANO,
|
||||
translation_key=ThinQProperty.UV_NANO,
|
||||
on_key="on",
|
||||
off_key="off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.WARM_MODE,
|
||||
translation_key=ThinQProperty.WARM_MODE,
|
||||
on_key="warm_on",
|
||||
off_key="warm_off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
),
|
||||
DeviceType.AIR_PURIFIER: (
|
||||
SwitchEntityDescription(
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.AIR_PURIFIER_OPERATION_MODE,
|
||||
translation_key="operation_power",
|
||||
),
|
||||
),
|
||||
DeviceType.DEHUMIDIFIER: (
|
||||
SwitchEntityDescription(
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.DEHUMIDIFIER_OPERATION_MODE,
|
||||
translation_key="operation_power",
|
||||
),
|
||||
),
|
||||
DeviceType.HUMIDIFIER: (
|
||||
SwitchEntityDescription(
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.HUMIDIFIER_OPERATION_MODE,
|
||||
translation_key="operation_power",
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.WARM_MODE,
|
||||
translation_key="humidity_warm_mode",
|
||||
on_key="warm_on",
|
||||
off_key="warm_off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.MOOD_LAMP_STATE,
|
||||
translation_key=ThinQProperty.MOOD_LAMP_STATE,
|
||||
on_key="on",
|
||||
off_key="off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.AUTO_MODE,
|
||||
translation_key=ThinQProperty.AUTO_MODE,
|
||||
on_key="auto_on",
|
||||
off_key="auto_off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.SLEEP_MODE,
|
||||
translation_key=ThinQProperty.SLEEP_MODE,
|
||||
on_key="sleep_on",
|
||||
off_key="sleep_off",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
),
|
||||
DeviceType.REFRIGERATOR: (
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.EXPRESS_MODE,
|
||||
translation_key=ThinQProperty.EXPRESS_MODE,
|
||||
on_key="true",
|
||||
off_key="false",
|
||||
),
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.RAPID_FREEZE,
|
||||
translation_key=ThinQProperty.RAPID_FREEZE,
|
||||
on_key="true",
|
||||
off_key="false",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
),
|
||||
DeviceType.SYSTEM_BOILER: (
|
||||
SwitchEntityDescription(
|
||||
key=ThinQProperty.BOILER_OPERATION_MODE, translation_key="operation_power"
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.HOT_WATER_MODE,
|
||||
translation_key=ThinQProperty.HOT_WATER_MODE,
|
||||
on_key="on",
|
||||
off_key="off",
|
||||
),
|
||||
),
|
||||
DeviceType.WINE_CELLAR: (
|
||||
ThinQSwitchEntityDescription(
|
||||
key=ThinQProperty.OPTIMAL_HUMIDITY,
|
||||
translation_key=ThinQProperty.OPTIMAL_HUMIDITY,
|
||||
on_key="on",
|
||||
off_key="off",
|
||||
),
|
||||
),
|
||||
}
|
||||
|
@ -61,7 +148,7 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up an entry for switch platform."""
|
||||
entities: list[ThinQSwitchEntity] = []
|
||||
for coordinator in entry.runtime_data.values():
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_SWITCH_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
|
@ -82,26 +169,56 @@ async def async_setup_entry(
|
|||
class ThinQSwitchEntity(ThinQEntity, SwitchEntity):
|
||||
"""Represent a thinq switch platform."""
|
||||
|
||||
entity_description: ThinQSwitchEntityDescription
|
||||
_attr_device_class = SwitchDeviceClass.SWITCH
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
if (key := self.entity_description.on_key) is not None:
|
||||
self._attr_is_on = self.data.value == key
|
||||
else:
|
||||
self._attr_is_on = self.data.is_on
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s",
|
||||
"[%s:%s] update status: %s -> %s",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.is_on,
|
||||
self.is_on,
|
||||
)
|
||||
self._attr_is_on = self.data.is_on
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the switch."""
|
||||
_LOGGER.debug("[%s] async_turn_on", self.name)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_on(self.property_id))
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_on id: %s",
|
||||
self.coordinator.device_name,
|
||||
self.name,
|
||||
self.property_id,
|
||||
)
|
||||
if (on_command := self.entity_description.on_key) is not None:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.post(self.property_id, on_command)
|
||||
)
|
||||
else:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_turn_on(self.property_id)
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the switch."""
|
||||
_LOGGER.debug("[%s] async_turn_off", self.name)
|
||||
await self.async_call_api(self.coordinator.api.async_turn_off(self.property_id))
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_turn_off id: %s",
|
||||
self.coordinator.device_name,
|
||||
self.name,
|
||||
self.property_id,
|
||||
)
|
||||
if (off_command := self.entity_description.off_key) is not None:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.post(self.property_id, off_command)
|
||||
)
|
||||
else:
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_turn_off(self.property_id)
|
||||
)
|
||||
|
|
172
homeassistant/components/lg_thinq/vacuum.py
Normal file
172
homeassistant/components/lg_thinq/vacuum.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
"""Support for vacuum entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
import logging
|
||||
|
||||
from thinqconnect import DeviceType
|
||||
from thinqconnect.integration import ExtendedProperty
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
StateVacuumEntityDescription,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import STATE_IDLE, STATE_PAUSED
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ThinqConfigEntry
|
||||
from .entity import ThinQEntity
|
||||
|
||||
DEVICE_TYPE_VACUUM_MAP: dict[DeviceType, tuple[StateVacuumEntityDescription, ...]] = {
|
||||
DeviceType.ROBOT_CLEANER: (
|
||||
StateVacuumEntityDescription(
|
||||
key=ExtendedProperty.VACUUM,
|
||||
name=None,
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class State(StrEnum):
|
||||
"""State of device."""
|
||||
|
||||
HOMING = "homing"
|
||||
PAUSE = "pause"
|
||||
RESUME = "resume"
|
||||
SLEEP = "sleep"
|
||||
START = "start"
|
||||
WAKE_UP = "wake_up"
|
||||
|
||||
|
||||
ROBOT_STATUS_TO_HA = {
|
||||
"charging": STATE_DOCKED,
|
||||
"diagnosis": STATE_IDLE,
|
||||
"homing": STATE_RETURNING,
|
||||
"initializing": STATE_IDLE,
|
||||
"macrosector": STATE_IDLE,
|
||||
"monitoring_detecting": STATE_IDLE,
|
||||
"monitoring_moving": STATE_IDLE,
|
||||
"monitoring_positioning": STATE_IDLE,
|
||||
"pause": STATE_PAUSED,
|
||||
"reservation": STATE_IDLE,
|
||||
"setdate": STATE_IDLE,
|
||||
"sleep": STATE_IDLE,
|
||||
"standby": STATE_IDLE,
|
||||
"working": STATE_CLEANING,
|
||||
"error": STATE_ERROR,
|
||||
}
|
||||
ROBOT_BATT_TO_HA = {
|
||||
"moveless": 5,
|
||||
"dock_level": 5,
|
||||
"low": 30,
|
||||
"mid": 50,
|
||||
"high": 90,
|
||||
"full": 100,
|
||||
"over_charge": 100,
|
||||
}
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ThinqConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an entry for vacuum platform."""
|
||||
entities: list[ThinQStateVacuumEntity] = []
|
||||
for coordinator in entry.runtime_data.coordinators.values():
|
||||
if (
|
||||
descriptions := DEVICE_TYPE_VACUUM_MAP.get(
|
||||
coordinator.api.device.device_type
|
||||
)
|
||||
) is not None:
|
||||
for description in descriptions:
|
||||
entities.extend(
|
||||
ThinQStateVacuumEntity(coordinator, description, property_id)
|
||||
for property_id in coordinator.api.get_active_idx(description.key)
|
||||
)
|
||||
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ThinQStateVacuumEntity(ThinQEntity, StateVacuumEntity):
|
||||
"""Represent a thinq vacuum platform."""
|
||||
|
||||
_attr_supported_features = (
|
||||
VacuumEntityFeature.SEND_COMMAND
|
||||
| VacuumEntityFeature.STATE
|
||||
| VacuumEntityFeature.BATTERY
|
||||
| VacuumEntityFeature.START
|
||||
| VacuumEntityFeature.PAUSE
|
||||
| VacuumEntityFeature.RETURN_HOME
|
||||
)
|
||||
|
||||
def _update_status(self) -> None:
|
||||
"""Update status itself."""
|
||||
super()._update_status()
|
||||
|
||||
# Update state.
|
||||
self._attr_state = ROBOT_STATUS_TO_HA[self.data.current_state]
|
||||
|
||||
# Update battery.
|
||||
if (level := self.data.battery) is not None:
|
||||
self._attr_battery_level = (
|
||||
level if isinstance(level, int) else ROBOT_BATT_TO_HA.get(level, 0)
|
||||
)
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] update status: %s -> %s (battery_level=%s)",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
self.data.current_state,
|
||||
self.state,
|
||||
self.battery_level,
|
||||
)
|
||||
|
||||
async def async_start(self, **kwargs) -> None:
|
||||
"""Start the device."""
|
||||
if self.data.current_state == State.SLEEP:
|
||||
value = State.WAKE_UP
|
||||
elif self._attr_state == STATE_PAUSED:
|
||||
value = State.RESUME
|
||||
else:
|
||||
value = State.START
|
||||
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_start", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_clean_operation_mode(self.property_id, value)
|
||||
)
|
||||
|
||||
async def async_pause(self, **kwargs) -> None:
|
||||
"""Pause the device."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_pause", self.coordinator.device_name, self.property_id
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_clean_operation_mode(
|
||||
self.property_id, State.PAUSE
|
||||
)
|
||||
)
|
||||
|
||||
async def async_return_to_base(self, **kwargs) -> None:
|
||||
"""Return device to dock."""
|
||||
_LOGGER.debug(
|
||||
"[%s:%s] async_return_to_base",
|
||||
self.coordinator.device_name,
|
||||
self.property_id,
|
||||
)
|
||||
await self.async_call_api(
|
||||
self.coordinator.api.async_set_clean_operation_mode(
|
||||
self.property_id, State.HOMING
|
||||
)
|
||||
)
|
|
@ -2803,7 +2803,7 @@ thermopro-ble==0.10.0
|
|||
thingspeak==1.0.0
|
||||
|
||||
# homeassistant.components.lg_thinq
|
||||
thinqconnect==0.9.7
|
||||
thinqconnect==0.9.8
|
||||
|
||||
# homeassistant.components.tikteck
|
||||
tikteck==0.4
|
||||
|
|
|
@ -2219,7 +2219,7 @@ thermobeacon-ble==0.7.0
|
|||
thermopro-ble==0.10.0
|
||||
|
||||
# homeassistant.components.lg_thinq
|
||||
thinqconnect==0.9.7
|
||||
thinqconnect==0.9.8
|
||||
|
||||
# homeassistant.components.tilt_ble
|
||||
tilt-ble==0.2.3
|
||||
|
|
Loading…
Add table
Reference in a new issue