Add DataUpdateCoordinator to Nanoleaf (#65950)

This commit is contained in:
Milan Meulemans 2022-02-06 23:11:52 +01:00 committed by GitHub
parent 275d4b9770
commit b1dcf7e0d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 60 deletions

View File

@ -3,15 +3,17 @@ from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import timedelta
import logging
from aionanoleaf import EffectsEvent, InvalidToken, Nanoleaf, StateEvent, Unavailable
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN
@ -23,6 +25,7 @@ class NanoleafEntryData:
"""Class for sharing data within the Nanoleaf integration."""
device: Nanoleaf
coordinator: DataUpdateCoordinator
event_listener: asyncio.Task
@ -31,26 +34,39 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
nanoleaf = Nanoleaf(
async_get_clientsession(hass), entry.data[CONF_HOST], entry.data[CONF_TOKEN]
)
try:
await nanoleaf.get_info()
except Unavailable as err:
raise ConfigEntryNotReady from err
except InvalidToken as err:
raise ConfigEntryAuthFailed from err
async def _callback_update_light_state(event: StateEvent | EffectsEvent) -> None:
async def async_get_state() -> None:
"""Get the state of the device."""
try:
await nanoleaf.get_info()
except Unavailable as err:
raise UpdateFailed from err
except InvalidToken as err:
raise ConfigEntryAuthFailed from err
coordinator = DataUpdateCoordinator(
hass,
logging.getLogger(__name__),
name=entry.title,
update_interval=timedelta(minutes=1),
update_method=async_get_state,
)
await coordinator.async_config_entry_first_refresh()
async def update_light_state_callback(event: StateEvent | EffectsEvent) -> None:
"""Receive state and effect event."""
async_dispatcher_send(hass, f"{DOMAIN}_update_light_{nanoleaf.serial_no}")
coordinator.async_set_updated_data(None)
event_listener = asyncio.create_task(
nanoleaf.listen_events(
state_callback=_callback_update_light_state,
effects_callback=_callback_update_light_state,
state_callback=update_light_state_callback,
effects_callback=update_light_state_callback,
)
)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = NanoleafEntryData(
nanoleaf, event_listener
nanoleaf, coordinator, event_listener
)
hass.config_entries.async_setup_platforms(entry, PLATFORMS)

View File

@ -7,6 +7,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import NanoleafEntryData
from .const import DOMAIN
@ -18,15 +19,17 @@ async def async_setup_entry(
) -> None:
"""Set up the Nanoleaf button."""
entry_data: NanoleafEntryData = hass.data[DOMAIN][entry.entry_id]
async_add_entities([NanoleafIdentifyButton(entry_data.device)])
async_add_entities(
[NanoleafIdentifyButton(entry_data.device, entry_data.coordinator)]
)
class NanoleafIdentifyButton(NanoleafEntity, ButtonEntity):
"""Representation of a Nanoleaf identify button."""
def __init__(self, nanoleaf: Nanoleaf) -> None:
def __init__(self, nanoleaf: Nanoleaf, coordinator: DataUpdateCoordinator) -> None:
"""Initialize the Nanoleaf button."""
super().__init__(nanoleaf)
super().__init__(nanoleaf, coordinator)
self._attr_unique_id = f"{nanoleaf.serial_no}_identify"
self._attr_name = f"Identify {nanoleaf.name}"
self._attr_icon = "mdi:magnify"

View File

@ -2,16 +2,21 @@
from aionanoleaf import Nanoleaf
from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import DOMAIN
class NanoleafEntity(Entity):
class NanoleafEntity(CoordinatorEntity):
"""Representation of a Nanoleaf entity."""
def __init__(self, nanoleaf: Nanoleaf) -> None:
def __init__(self, nanoleaf: Nanoleaf, coordinator: DataUpdateCoordinator) -> None:
"""Initialize an Nanoleaf entity."""
super().__init__(coordinator)
self._nanoleaf = nanoleaf
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, nanoleaf.serial_no)},

View File

@ -1,12 +1,11 @@
"""Support for Nanoleaf Lights."""
from __future__ import annotations
from datetime import timedelta
import logging
import math
from typing import Any
from aionanoleaf import Nanoleaf, Unavailable
from aionanoleaf import Nanoleaf
import voluptuous as vol
from homeassistant.components.light import (
@ -25,11 +24,11 @@ from homeassistant.components.light import (
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util.color import (
color_temperature_kelvin_to_mired as kelvin_to_mired,
color_temperature_mired_to_kelvin as mired_to_kelvin,
@ -52,8 +51,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(minutes=5)
async def async_setup_platform(
hass: HomeAssistant,
@ -82,15 +79,15 @@ async def async_setup_entry(
) -> None:
"""Set up the Nanoleaf light."""
entry_data: NanoleafEntryData = hass.data[DOMAIN][entry.entry_id]
async_add_entities([NanoleafLight(entry_data.device)])
async_add_entities([NanoleafLight(entry_data.device, entry_data.coordinator)])
class NanoleafLight(NanoleafEntity, LightEntity):
"""Representation of a Nanoleaf Light."""
def __init__(self, nanoleaf: Nanoleaf) -> None:
def __init__(self, nanoleaf: Nanoleaf, coordinator: DataUpdateCoordinator) -> None:
"""Initialize the Nanoleaf light."""
super().__init__(nanoleaf)
super().__init__(nanoleaf, coordinator)
self._attr_unique_id = nanoleaf.serial_no
self._attr_name = nanoleaf.name
self._attr_min_mireds = math.ceil(1000000 / nanoleaf.color_temperature_max)
@ -186,35 +183,3 @@ class NanoleafLight(NanoleafEntity, LightEntity):
"""Instruct the light to turn off."""
transition: float | None = kwargs.get(ATTR_TRANSITION)
await self._nanoleaf.turn_off(None if transition is None else int(transition))
async def async_update(self) -> None:
"""Fetch new state data for this light."""
try:
await self._nanoleaf.get_info()
except Unavailable:
if self.available:
_LOGGER.warning("Could not connect to %s", self.name)
self._attr_available = False
return
if not self.available:
_LOGGER.info("Fetching %s data recovered", self.name)
self._attr_available = True
@callback
def async_handle_update(self) -> None:
"""Handle state update."""
self.async_write_ha_state()
if not self.available:
_LOGGER.info("Connection to %s recovered", self.name)
self._attr_available = True
async def async_added_to_hass(self) -> None:
"""Handle entity being added to Home Assistant."""
await super().async_added_to_hass()
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{DOMAIN}_update_light_{self._nanoleaf.serial_no}",
self.async_handle_update,
)
)