Add coordinator to Knocki (#120251)
parent
c04a6cc639
commit
f3a1ca6d54
|
@ -2,27 +2,18 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from knocki import KnockiClient, KnockiConnectionError, Trigger
|
||||
from knocki import EventType, KnockiClient
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_TOKEN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .coordinator import KnockiCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.EVENT]
|
||||
|
||||
type KnockiConfigEntry = ConfigEntry[KnockiData]
|
||||
|
||||
|
||||
@dataclass
|
||||
class KnockiData:
|
||||
"""Knocki data."""
|
||||
|
||||
client: KnockiClient
|
||||
triggers: list[Trigger]
|
||||
type KnockiConfigEntry = ConfigEntry[KnockiCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: KnockiConfigEntry) -> bool:
|
||||
|
@ -31,12 +22,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: KnockiConfigEntry) -> bo
|
|||
session=async_get_clientsession(hass), token=entry.data[CONF_TOKEN]
|
||||
)
|
||||
|
||||
try:
|
||||
triggers = await client.get_triggers()
|
||||
except KnockiConnectionError as exc:
|
||||
raise ConfigEntryNotReady from exc
|
||||
coordinator = KnockiCoordinator(hass, client)
|
||||
|
||||
entry.runtime_data = KnockiData(client=client, triggers=triggers)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
entry.async_on_unload(
|
||||
client.register_listener(EventType.CREATED, coordinator.add_trigger)
|
||||
)
|
||||
|
||||
entry.runtime_data = coordinator
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
"""Update coordinator for Knocki integration."""
|
||||
|
||||
from knocki import Event, KnockiClient, KnockiConnectionError, Trigger
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
|
||||
class KnockiCoordinator(DataUpdateCoordinator[dict[int, Trigger]]):
|
||||
"""The Knocki coordinator."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, client: KnockiClient) -> None:
|
||||
"""Initialize the coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
logger=LOGGER,
|
||||
name=DOMAIN,
|
||||
)
|
||||
self.client = client
|
||||
|
||||
async def _async_update_data(self) -> dict[int, Trigger]:
|
||||
try:
|
||||
triggers = await self.client.get_triggers()
|
||||
except KnockiConnectionError as exc:
|
||||
raise UpdateFailed from exc
|
||||
return {trigger.details.trigger_id: trigger for trigger in triggers}
|
||||
|
||||
def add_trigger(self, event: Event) -> None:
|
||||
"""Add a trigger to the coordinator."""
|
||||
self.async_set_updated_data(
|
||||
{**self.data, event.payload.details.trigger_id: event.payload}
|
||||
)
|
|
@ -3,7 +3,7 @@
|
|||
from knocki import Event, EventType, KnockiClient, Trigger
|
||||
|
||||
from homeassistant.components.event import EventEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
|
@ -17,10 +17,26 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Knocki from a config entry."""
|
||||
entry_data = entry.runtime_data
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
added_triggers = set(coordinator.data)
|
||||
|
||||
@callback
|
||||
def _async_add_entities() -> None:
|
||||
current_triggers = set(coordinator.data)
|
||||
new_triggers = current_triggers - added_triggers
|
||||
added_triggers.update(new_triggers)
|
||||
if new_triggers:
|
||||
async_add_entities(
|
||||
KnockiTrigger(coordinator.data[trigger], coordinator.client)
|
||||
for trigger in new_triggers
|
||||
)
|
||||
|
||||
coordinator.async_add_listener(_async_add_entities)
|
||||
|
||||
async_add_entities(
|
||||
KnockiTrigger(trigger, entry_data.client) for trigger in entry_data.triggers
|
||||
KnockiTrigger(trigger, coordinator.client)
|
||||
for trigger in coordinator.data.values()
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -7,13 +7,14 @@ from knocki import Event, EventType, Trigger, TriggerDetails
|
|||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.knocki.const import DOMAIN
|
||||
from homeassistant.const import STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.common import MockConfigEntry, load_json_array_fixture, snapshot_platform
|
||||
|
||||
|
||||
async def test_entities(
|
||||
|
@ -73,3 +74,25 @@ async def test_subscription(
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert mock_knocki_client.register_listener.return_value.called
|
||||
|
||||
|
||||
async def test_adding_runtime_entities(
|
||||
hass: HomeAssistant,
|
||||
mock_knocki_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test we can create devices on runtime."""
|
||||
mock_knocki_client.get_triggers.return_value = []
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert not hass.states.get("event.knc1_w_00000214_aaaa")
|
||||
|
||||
add_trigger_function: Callable[[Event], None] = (
|
||||
mock_knocki_client.register_listener.call_args[0][1]
|
||||
)
|
||||
trigger = Trigger.from_dict(load_json_array_fixture("triggers.json", DOMAIN)[0])
|
||||
|
||||
add_trigger_function(Event(EventType.CREATED, trigger))
|
||||
|
||||
assert hass.states.get("event.knc1_w_00000214_aaaa") is not None
|
||||
|
|
Loading…
Reference in New Issue