Skip to content

Commit

Permalink
Add DataUpdateCoordinator to Nanoleaf (home-assistant#65950)
Browse files Browse the repository at this point in the history
  • Loading branch information
milanmeu authored Feb 6, 2022
1 parent 275d4b9 commit b1dcf7e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 61 deletions.
44 changes: 30 additions & 14 deletions homeassistant/components/nanoleaf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@

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

Expand All @@ -23,6 +25,7 @@ class NanoleafEntryData:
"""Class for sharing data within the Nanoleaf integration."""

device: Nanoleaf
coordinator: DataUpdateCoordinator
event_listener: asyncio.Task


Expand All @@ -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)
Expand Down
9 changes: 6 additions & 3 deletions homeassistant/components/nanoleaf/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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
Expand All @@ -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"
Expand Down
11 changes: 8 additions & 3 deletions homeassistant/components/nanoleaf/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand Down
47 changes: 6 additions & 41 deletions homeassistant/components/nanoleaf/light.py
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -25,11 +24,11 @@
)
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,
Expand All @@ -52,8 +51,6 @@

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = timedelta(minutes=5)


async def async_setup_platform(
hass: HomeAssistant,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -186,35 +183,3 @@ async def async_turn_off(self, **kwargs: Any) -> None:
"""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,
)
)

0 comments on commit b1dcf7e

Please sign in to comment.