From 130b6559a68a6acae79138feae7c70ba78560580 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Tue, 10 Sep 2024 15:30:30 +0200 Subject: [PATCH] Add coordinator to Daikin (#124394) * Add coordinator to Daikin * Add coordinator to Daikin * Fix * Add seconds --- homeassistant/components/daikin/__init__.py | 116 +++++------------- homeassistant/components/daikin/climate.py | 73 +++++------ .../components/daikin/coordinator.py | 30 +++++ homeassistant/components/daikin/entity.py | 25 ++++ homeassistant/components/daikin/sensor.py | 20 ++- homeassistant/components/daikin/switch.py | 82 +++++-------- tests/components/daikin/test_init.py | 13 +- 7 files changed, 162 insertions(+), 197 deletions(-) create mode 100644 homeassistant/components/daikin/coordinator.py create mode 100644 homeassistant/components/daikin/entity.py diff --git a/homeassistant/components/daikin/__init__.py b/homeassistant/components/daikin/__init__.py index 4da6bcee50b..c58578071ee 100644 --- a/homeassistant/components/daikin/__init__.py +++ b/homeassistant/components/daikin/__init__.py @@ -3,9 +3,7 @@ from __future__ import annotations import asyncio -from datetime import timedelta import logging -from typing import Any from aiohttp import ClientConnectionError from pydaikin.daikin_base import Appliance @@ -23,15 +21,13 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo -from homeassistant.util import Throttle +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from .const import DOMAIN, KEY_MAC, TIMEOUT +from .coordinator import DaikinCoordinator _LOGGER = logging.getLogger(__name__) -PARALLEL_UPDATES = 0 -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) PLATFORMS = [Platform.CLIMATE, Platform.SENSOR, Platform.SWITCH] @@ -43,19 +39,32 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if entry.unique_id is None or ".local" in entry.unique_id: hass.config_entries.async_update_entry(entry, unique_id=conf[KEY_MAC]) - daikin_api = await daikin_api_setup( - hass, - conf[CONF_HOST], - conf.get(CONF_API_KEY), - conf.get(CONF_UUID), - conf.get(CONF_PASSWORD), - ) - if not daikin_api: - return False + session = async_get_clientsession(hass) + host = conf[CONF_HOST] + try: + async with asyncio.timeout(TIMEOUT): + device: Appliance = await DaikinFactory( + host, + session, + key=entry.data.get(CONF_API_KEY), + uuid=entry.data.get(CONF_UUID), + password=entry.data.get(CONF_PASSWORD), + ) + _LOGGER.debug("Connection to %s successful", host) + except TimeoutError as err: + _LOGGER.debug("Connection to %s timed out in 60 seconds", host) + raise ConfigEntryNotReady from err + except ClientConnectionError as err: + _LOGGER.debug("ClientConnectionError to %s", host) + raise ConfigEntryNotReady from err - await async_migrate_unique_id(hass, entry, daikin_api) + coordinator = DaikinCoordinator(hass, device) - hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api}) + await coordinator.async_config_entry_first_refresh() + + await async_migrate_unique_id(hass, entry, device) + + hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True @@ -70,83 +79,16 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return unload_ok -async def daikin_api_setup( - hass: HomeAssistant, - host: str, - key: str | None, - uuid: str | None, - password: str | None, -) -> DaikinApi | None: - """Create a Daikin instance only once.""" - - session = async_get_clientsession(hass) - try: - async with asyncio.timeout(TIMEOUT): - device: Appliance = await DaikinFactory( - host, session, key=key, uuid=uuid, password=password - ) - _LOGGER.debug("Connection to %s successful", host) - except TimeoutError as err: - _LOGGER.debug("Connection to %s timed out", host) - raise ConfigEntryNotReady from err - except ClientConnectionError as err: - _LOGGER.debug("ClientConnectionError to %s", host) - raise ConfigEntryNotReady from err - except Exception: # noqa: BLE001 - _LOGGER.error("Unexpected error creating device %s", host) - return None - - return DaikinApi(device) - - -class DaikinApi: - """Keep the Daikin instance in one place and centralize the update.""" - - def __init__(self, device: Appliance) -> None: - """Initialize the Daikin Handle.""" - self.device = device - self.name = device.values.get("name", "Daikin AC") - self.ip_address = device.device_ip - self._available = True - - @Throttle(MIN_TIME_BETWEEN_UPDATES) - async def async_update(self, **kwargs: Any) -> None: - """Pull the latest data from Daikin.""" - try: - await self.device.update_status() - self._available = True - except ClientConnectionError: - _LOGGER.warning("Connection failed for %s", self.ip_address) - self._available = False - - @property - def available(self) -> bool: - """Return True if entity is available.""" - return self._available - - @property - def device_info(self) -> DeviceInfo: - """Return a device description for device registry.""" - info = self.device.values - return DeviceInfo( - connections={(CONNECTION_NETWORK_MAC, self.device.mac)}, - manufacturer="Daikin", - model=info.get("model"), - name=info.get("name"), - sw_version=info.get("ver", "").replace("_", "."), - ) - - async def async_migrate_unique_id( - hass: HomeAssistant, config_entry: ConfigEntry, api: DaikinApi + hass: HomeAssistant, config_entry: ConfigEntry, device: Appliance ) -> None: """Migrate old entry.""" dev_reg = dr.async_get(hass) ent_reg = er.async_get(hass) old_unique_id = config_entry.unique_id - new_unique_id = api.device.mac + new_unique_id = device.mac new_mac = dr.format_mac(new_unique_id) - new_name = api.name + new_name = device.values.get("name", "Daikin AC") @callback def _update_unique_id(entity_entry: er.RegistryEntry) -> dict[str, str] | None: diff --git a/homeassistant/components/daikin/climate.py b/homeassistant/components/daikin/climate.py index fc54d4b0427..22510330cc5 100644 --- a/homeassistant/components/daikin/climate.py +++ b/homeassistant/components/daikin/climate.py @@ -34,7 +34,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN as DAIKIN_DOMAIN, DaikinApi +from . import DOMAIN as DAIKIN_DOMAIN from .const import ( ATTR_INSIDE_TEMPERATURE, ATTR_OUTSIDE_TEMPERATURE, @@ -42,6 +42,8 @@ from .const import ( ATTR_STATE_ON, ATTR_TARGET_TEMPERATURE, ) +from .coordinator import DaikinCoordinator +from .entity import DaikinEntity _LOGGER = logging.getLogger(__name__) @@ -111,7 +113,7 @@ async def async_setup_entry( ) -> None: """Set up Daikin climate based on config_entry.""" daikin_api = hass.data[DAIKIN_DOMAIN].get(entry.entry_id) - async_add_entities([DaikinClimate(daikin_api)], update_before_add=True) + async_add_entities([DaikinClimate(daikin_api)]) def format_target_temperature(target_temperature: float) -> str: @@ -119,11 +121,10 @@ def format_target_temperature(target_temperature: float) -> str: return str(round(float(target_temperature) * 2, 0) / 2).rstrip("0").rstrip(".") -class DaikinClimate(ClimateEntity): +class DaikinClimate(DaikinEntity, ClimateEntity): """Representation of a Daikin HVAC.""" _attr_name = None - _attr_has_entity_name = True _attr_temperature_unit = UnitOfTemperature.CELSIUS _attr_hvac_modes = list(HA_STATE_TO_DAIKIN) _attr_target_temperature_step = 1 @@ -131,13 +132,11 @@ class DaikinClimate(ClimateEntity): _attr_swing_modes: list[str] _enable_turn_on_off_backwards_compatibility = False - def __init__(self, api: DaikinApi) -> None: + def __init__(self, coordinator: DaikinCoordinator) -> None: """Initialize the climate device.""" - - self._api = api - self._attr_fan_modes = api.device.fan_rate - self._attr_swing_modes = api.device.swing_modes - self._attr_device_info = api.device_info + super().__init__(coordinator) + self._attr_fan_modes = self.device.fan_rate + self._attr_swing_modes = self.device.swing_modes self._list: dict[str, list[Any]] = { ATTR_HVAC_MODE: self._attr_hvac_modes, ATTR_FAN_MODE: self._attr_fan_modes, @@ -150,13 +149,13 @@ class DaikinClimate(ClimateEntity): | ClimateEntityFeature.TARGET_TEMPERATURE ) - if api.device.support_away_mode or api.device.support_advanced_modes: + if self.device.support_away_mode or self.device.support_advanced_modes: self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE - if api.device.support_fan_rate: + if self.device.support_fan_rate: self._attr_supported_features |= ClimateEntityFeature.FAN_MODE - if api.device.support_swing_mode: + if self.device.support_swing_mode: self._attr_supported_features |= ClimateEntityFeature.SWING_MODE async def _set(self, settings: dict[str, Any]) -> None: @@ -185,22 +184,22 @@ class DaikinClimate(ClimateEntity): _LOGGER.error("Invalid temperature %s", value) if values: - await self._api.device.set(values) + await self.device.set(values) @property def unique_id(self) -> str: """Return a unique ID.""" - return self._api.device.mac + return self.device.mac @property def current_temperature(self) -> float | None: """Return the current temperature.""" - return self._api.device.inside_temperature + return self.device.inside_temperature @property def target_temperature(self) -> float | None: """Return the temperature we try to reach.""" - return self._api.device.target_temperature + return self.device.target_temperature async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" @@ -212,8 +211,8 @@ class DaikinClimate(ClimateEntity): ret = HA_STATE_TO_CURRENT_HVAC.get(self.hvac_mode) if ( ret in (HVACAction.COOLING, HVACAction.HEATING) - and self._api.device.support_compressor_frequency - and self._api.device.compressor_frequency == 0 + and self.device.support_compressor_frequency + and self.device.compressor_frequency == 0 ): return HVACAction.IDLE return ret @@ -221,7 +220,7 @@ class DaikinClimate(ClimateEntity): @property def hvac_mode(self) -> HVACMode: """Return current operation ie. heat, cool, idle.""" - daikin_mode = self._api.device.represent(HA_ATTR_TO_DAIKIN[ATTR_HVAC_MODE])[1] + daikin_mode = self.device.represent(HA_ATTR_TO_DAIKIN[ATTR_HVAC_MODE])[1] return DAIKIN_TO_HA_STATE.get(daikin_mode, HVACMode.HEAT_COOL) async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: @@ -231,7 +230,7 @@ class DaikinClimate(ClimateEntity): @property def fan_mode(self) -> str: """Return the fan setting.""" - return self._api.device.represent(HA_ATTR_TO_DAIKIN[ATTR_FAN_MODE])[1].title() + return self.device.represent(HA_ATTR_TO_DAIKIN[ATTR_FAN_MODE])[1].title() async def async_set_fan_mode(self, fan_mode: str) -> None: """Set fan mode.""" @@ -240,7 +239,7 @@ class DaikinClimate(ClimateEntity): @property def swing_mode(self) -> str: """Return the fan setting.""" - return self._api.device.represent(HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE])[1].title() + return self.device.represent(HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE])[1].title() async def async_set_swing_mode(self, swing_mode: str) -> None: """Set new target temperature.""" @@ -250,18 +249,18 @@ class DaikinClimate(ClimateEntity): def preset_mode(self) -> str: """Return the preset_mode.""" if ( - self._api.device.represent(HA_ATTR_TO_DAIKIN[ATTR_PRESET_MODE])[1] + self.device.represent(HA_ATTR_TO_DAIKIN[ATTR_PRESET_MODE])[1] == HA_PRESET_TO_DAIKIN[PRESET_AWAY] ): return PRESET_AWAY if ( HA_PRESET_TO_DAIKIN[PRESET_BOOST] - in self._api.device.represent(DAIKIN_ATTR_ADVANCED)[1] + in self.device.represent(DAIKIN_ATTR_ADVANCED)[1] ): return PRESET_BOOST if ( HA_PRESET_TO_DAIKIN[PRESET_ECO] - in self._api.device.represent(DAIKIN_ATTR_ADVANCED)[1] + in self.device.represent(DAIKIN_ATTR_ADVANCED)[1] ): return PRESET_ECO return PRESET_NONE @@ -269,23 +268,23 @@ class DaikinClimate(ClimateEntity): async def async_set_preset_mode(self, preset_mode: str) -> None: """Set preset mode.""" if preset_mode == PRESET_AWAY: - await self._api.device.set_holiday(ATTR_STATE_ON) + await self.device.set_holiday(ATTR_STATE_ON) elif preset_mode == PRESET_BOOST: - await self._api.device.set_advanced_mode( + await self.device.set_advanced_mode( HA_PRESET_TO_DAIKIN[PRESET_BOOST], ATTR_STATE_ON ) elif preset_mode == PRESET_ECO: - await self._api.device.set_advanced_mode( + await self.device.set_advanced_mode( HA_PRESET_TO_DAIKIN[PRESET_ECO], ATTR_STATE_ON ) elif self.preset_mode == PRESET_AWAY: - await self._api.device.set_holiday(ATTR_STATE_OFF) + await self.device.set_holiday(ATTR_STATE_OFF) elif self.preset_mode == PRESET_BOOST: - await self._api.device.set_advanced_mode( + await self.device.set_advanced_mode( HA_PRESET_TO_DAIKIN[PRESET_BOOST], ATTR_STATE_OFF ) elif self.preset_mode == PRESET_ECO: - await self._api.device.set_advanced_mode( + await self.device.set_advanced_mode( HA_PRESET_TO_DAIKIN[PRESET_ECO], ATTR_STATE_OFF ) @@ -293,22 +292,18 @@ class DaikinClimate(ClimateEntity): def preset_modes(self) -> list[str]: """List of available preset modes.""" ret = [PRESET_NONE] - if self._api.device.support_away_mode: + if self.device.support_away_mode: ret.append(PRESET_AWAY) - if self._api.device.support_advanced_modes: + if self.device.support_advanced_modes: ret += [PRESET_ECO, PRESET_BOOST] return ret - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() - async def async_turn_on(self) -> None: """Turn device on.""" - await self._api.device.set({}) + await self.device.set({}) async def async_turn_off(self) -> None: """Turn device off.""" - await self._api.device.set( + await self.device.set( {HA_ATTR_TO_DAIKIN[ATTR_HVAC_MODE]: HA_STATE_TO_DAIKIN[HVACMode.OFF]} ) diff --git a/homeassistant/components/daikin/coordinator.py b/homeassistant/components/daikin/coordinator.py new file mode 100644 index 00000000000..35d998b4ba2 --- /dev/null +++ b/homeassistant/components/daikin/coordinator.py @@ -0,0 +1,30 @@ +"""Coordinator for Daikin integration.""" + +from datetime import timedelta +import logging + +from pydaikin.daikin_base import Appliance + +from homeassistant.core import HomeAssistant +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +class DaikinCoordinator(DataUpdateCoordinator[None]): + """Class to manage fetching Daikin data.""" + + def __init__(self, hass: HomeAssistant, device: Appliance) -> None: + """Initialize global Daikin data updater.""" + super().__init__( + hass, + _LOGGER, + name=device.values.get("name", DOMAIN), + update_interval=timedelta(seconds=60), + ) + self.device = device + + async def _async_update_data(self) -> None: + await self.device.update_status() diff --git a/homeassistant/components/daikin/entity.py b/homeassistant/components/daikin/entity.py new file mode 100644 index 00000000000..704ce226416 --- /dev/null +++ b/homeassistant/components/daikin/entity.py @@ -0,0 +1,25 @@ +"""Base entity for Daikin.""" + +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .coordinator import DaikinCoordinator + + +class DaikinEntity(CoordinatorEntity[DaikinCoordinator]): + """Base entity for Daikin.""" + + _attr_has_entity_name = True + + def __init__(self, coordinator: DaikinCoordinator) -> None: + """Initialize the entity.""" + super().__init__(coordinator) + self.device = coordinator.device + info = self.device.values + self._attr_device_info = DeviceInfo( + connections={(CONNECTION_NETWORK_MAC, self.device.mac)}, + manufacturer="Daikin", + model=info.get("model"), + name=info.get("name"), + sw_version=info.get("ver", "").replace("_", "."), + ) diff --git a/homeassistant/components/daikin/sensor.py b/homeassistant/components/daikin/sensor.py index a17a80f2065..bcf23068a63 100644 --- a/homeassistant/components/daikin/sensor.py +++ b/homeassistant/components/daikin/sensor.py @@ -25,7 +25,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN as DAIKIN_DOMAIN, DaikinApi +from . import DOMAIN as DAIKIN_DOMAIN from .const import ( ATTR_COMPRESSOR_FREQUENCY, ATTR_COOL_ENERGY, @@ -38,6 +38,8 @@ from .const import ( ATTR_TOTAL_ENERGY_TODAY, ATTR_TOTAL_POWER, ) +from .coordinator import DaikinCoordinator +from .entity import DaikinEntity @dataclass(frozen=True, kw_only=True) @@ -173,26 +175,20 @@ async def async_setup_entry( async_add_entities(entities) -class DaikinSensor(SensorEntity): +class DaikinSensor(DaikinEntity, SensorEntity): """Representation of a Sensor.""" - _attr_has_entity_name = True entity_description: DaikinSensorEntityDescription def __init__( - self, api: DaikinApi, description: DaikinSensorEntityDescription + self, coordinator: DaikinCoordinator, description: DaikinSensorEntityDescription ) -> None: """Initialize the sensor.""" + super().__init__(coordinator) self.entity_description = description - self._attr_device_info = api.device_info - self._attr_unique_id = f"{api.device.mac}-{description.key}" - self._api = api + self._attr_unique_id = f"{self.device.mac}-{description.key}" @property def native_value(self) -> float | None: """Return the state of the sensor.""" - return self.entity_description.value_func(self._api.device) - - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() + return self.entity_description.value_func(self.device) diff --git a/homeassistant/components/daikin/switch.py b/homeassistant/components/daikin/switch.py index af94e98a337..309b21d2cb9 100644 --- a/homeassistant/components/daikin/switch.py +++ b/homeassistant/components/daikin/switch.py @@ -10,7 +10,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN as DAIKIN_DOMAIN, DaikinApi +from . import DOMAIN +from .coordinator import DaikinCoordinator +from .entity import DaikinEntity DAIKIN_ATTR_ADVANCED = "adv" DAIKIN_ATTR_STREAMER = "streamer" @@ -34,15 +36,13 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up Daikin climate based on config_entry.""" - daikin_api: DaikinApi = hass.data[DAIKIN_DOMAIN][entry.entry_id] - switches: list[DaikinZoneSwitch | DaikinStreamerSwitch | DaikinToggleSwitch] = [] + daikin_api: DaikinCoordinator = hass.data[DOMAIN][entry.entry_id] + switches: list[SwitchEntity] = [] if zones := daikin_api.device.zones: switches.extend( - [ - DaikinZoneSwitch(daikin_api, zone_id) - for zone_id, zone in enumerate(zones) - if zone[0] != "-" - ] + DaikinZoneSwitch(daikin_api, zone_id) + for zone_id, zone in enumerate(zones) + if zone[0] != "-" ) if daikin_api.device.support_advanced_modes: # It isn't possible to find out from the API responses if a specific @@ -53,100 +53,80 @@ async def async_setup_entry( async_add_entities(switches) -class DaikinZoneSwitch(SwitchEntity): +class DaikinZoneSwitch(DaikinEntity, SwitchEntity): """Representation of a zone.""" - _attr_has_entity_name = True _attr_translation_key = "zone" - def __init__(self, api: DaikinApi, zone_id: int) -> None: + def __init__(self, coordinator: DaikinCoordinator, zone_id: int) -> None: """Initialize the zone.""" - self._api = api + super().__init__(coordinator) self._zone_id = zone_id - self._attr_device_info = api.device_info - self._attr_unique_id = f"{api.device.mac}-zone{zone_id}" + self._attr_unique_id = f"{self.device.mac}-zone{zone_id}" @property def name(self) -> str: """Return the name of the sensor.""" - return self._api.device.zones[self._zone_id][0] + return self.device.zones[self._zone_id][0] @property def is_on(self) -> bool: """Return the state of the sensor.""" - return self._api.device.zones[self._zone_id][1] == "1" - - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() + return self.device.zones[self._zone_id][1] == "1" async def async_turn_on(self, **kwargs: Any) -> None: """Turn the zone on.""" - await self._api.device.set_zone(self._zone_id, "zone_onoff", "1") + await self.device.set_zone(self._zone_id, "zone_onoff", "1") async def async_turn_off(self, **kwargs: Any) -> None: """Turn the zone off.""" - await self._api.device.set_zone(self._zone_id, "zone_onoff", "0") + await self.device.set_zone(self._zone_id, "zone_onoff", "0") -class DaikinStreamerSwitch(SwitchEntity): +class DaikinStreamerSwitch(DaikinEntity, SwitchEntity): """Streamer state.""" _attr_name = "Streamer" - _attr_has_entity_name = True _attr_translation_key = "streamer" - def __init__(self, api: DaikinApi) -> None: - """Initialize streamer switch.""" - self._api = api - self._attr_device_info = api.device_info - self._attr_unique_id = f"{api.device.mac}-streamer" + def __init__(self, coordinator: DaikinCoordinator) -> None: + """Initialize switch.""" + super().__init__(coordinator) + self._attr_unique_id = f"{self.device.mac}-streamer" @property def is_on(self) -> bool: """Return the state of the sensor.""" - return ( - DAIKIN_ATTR_STREAMER in self._api.device.represent(DAIKIN_ATTR_ADVANCED)[1] - ) - - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() + return DAIKIN_ATTR_STREAMER in self.device.represent(DAIKIN_ATTR_ADVANCED)[1] async def async_turn_on(self, **kwargs: Any) -> None: """Turn the zone on.""" - await self._api.device.set_streamer("on") + await self.device.set_streamer("on") async def async_turn_off(self, **kwargs: Any) -> None: """Turn the zone off.""" - await self._api.device.set_streamer("off") + await self.device.set_streamer("off") -class DaikinToggleSwitch(SwitchEntity): +class DaikinToggleSwitch(DaikinEntity, SwitchEntity): """Switch state.""" - _attr_has_entity_name = True _attr_translation_key = "toggle" - def __init__(self, api: DaikinApi) -> None: + def __init__(self, coordinator: DaikinCoordinator) -> None: """Initialize switch.""" - self._api = api - self._attr_device_info = api.device_info - self._attr_unique_id = f"{self._api.device.mac}-toggle" + super().__init__(coordinator) + self._attr_unique_id = f"{self.device.mac}-toggle" @property def is_on(self) -> bool: """Return the state of the sensor.""" - return "off" not in self._api.device.represent(DAIKIN_ATTR_MODE) - - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() + return "off" not in self.device.represent(DAIKIN_ATTR_MODE) async def async_turn_on(self, **kwargs: Any) -> None: """Turn the zone on.""" - await self._api.device.set({}) + await self.device.set({}) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the zone off.""" - await self._api.device.set({DAIKIN_ATTR_MODE: "off"}) + await self.device.set({DAIKIN_ATTR_MODE: "off"}) diff --git a/tests/components/daikin/test_init.py b/tests/components/daikin/test_init.py index b3d18467d33..2380d5ad798 100644 --- a/tests/components/daikin/test_init.py +++ b/tests/components/daikin/test_init.py @@ -7,10 +7,10 @@ from aiohttp import ClientConnectionError from freezegun.api import FrozenDateTimeFactory import pytest -from homeassistant.components.daikin import DaikinApi, update_unique_id +from homeassistant.components.daikin import update_unique_id from homeassistant.components.daikin.const import DOMAIN, KEY_MAC from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import CONF_HOST +from homeassistant.const import CONF_HOST, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -183,18 +183,15 @@ async def test_client_update_connection_error( await hass.config_entries.async_setup(config_entry.entry_id) - api: DaikinApi = hass.data[DOMAIN][config_entry.entry_id] - - assert api.available is True + assert hass.states.get("climate.daikinap00000").state != STATE_UNAVAILABLE type(mock_daikin).update_status.side_effect = ClientConnectionError - freezer.tick(timedelta(seconds=90)) + freezer.tick(timedelta(seconds=60)) async_fire_time_changed(hass) - await hass.async_block_till_done() - assert api.available is False + assert hass.states.get("climate.daikinap00000").state == STATE_UNAVAILABLE assert mock_daikin.update_status.call_count == 2