Remove Knocki triggers on runtime (#120452)

* Bump Knocki to 0.2.0

* Remove triggers on runtime in Knocki

* Fix
This commit is contained in:
Joost Lekkerkerker 2024-06-26 09:52:05 +02:00 committed by GitHub
parent 82b8b73b8a
commit 59959141af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 92 additions and 3 deletions

View File

@ -2,7 +2,7 @@
from __future__ import annotations
from knocki import EventType, KnockiClient
from knocki import Event, EventType, KnockiClient
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_TOKEN, Platform
@ -30,6 +30,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: KnockiConfigEntry) -> bo
client.register_listener(EventType.CREATED, coordinator.add_trigger)
)
async def _refresh_coordinator(_: Event) -> None:
await coordinator.async_refresh()
entry.async_on_unload(
client.register_listener(EventType.DELETED, _refresh_coordinator)
)
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -2,7 +2,9 @@
from knocki import Event, KnockiClient, KnockiConnectionError, Trigger
from homeassistant.components.event import DOMAIN as EVENT_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, LOGGER
@ -19,12 +21,20 @@ class KnockiCoordinator(DataUpdateCoordinator[dict[int, Trigger]]):
name=DOMAIN,
)
self.client = client
self._known_triggers: set[tuple[str, int]] = set()
async def _async_update_data(self) -> dict[int, Trigger]:
try:
triggers = await self.client.get_triggers()
except KnockiConnectionError as exc:
raise UpdateFailed from exc
current_triggers = {
(trigger.device_id, trigger.details.trigger_id) for trigger in triggers
}
removed_triggers = self._known_triggers - current_triggers
for trigger in removed_triggers:
await self._delete_device(trigger)
self._known_triggers = current_triggers
return {trigger.details.trigger_id: trigger for trigger in triggers}
def add_trigger(self, event: Event) -> None:
@ -32,3 +42,16 @@ class KnockiCoordinator(DataUpdateCoordinator[dict[int, Trigger]]):
self.async_set_updated_data(
{**self.data, event.payload.details.trigger_id: event.payload}
)
self._known_triggers.add(
(event.payload.device_id, event.payload.details.trigger_id)
)
async def _delete_device(self, trigger: tuple[str, int]) -> None:
"""Delete a device from the coordinator."""
device_id, trigger_id = trigger
entity_registry = er.async_get(self.hass)
entity_entry = entity_registry.async_get_entity_id(
EVENT_DOMAIN, DOMAIN, f"{device_id}_{trigger_id}"
)
if entity_entry:
entity_registry.async_remove(entity_entry)

View File

@ -0,0 +1,30 @@
[
{
"device": "KNC1-W-00000214",
"gesture": "d060b870-15ba-42c9-a932-2d2951087152",
"details": {
"description": "Eeee",
"name": "Aaaa",
"id": 31
},
"type": "homeassistant",
"user": "7a4d5bf9-01b1-413b-bb4d-77728e931dcc",
"updatedAt": 1716378013721,
"createdAt": 1716378013721,
"id": "1a050b25-7fed-4e0e-b5af-792b8b4650de"
},
{
"device": "KNC1-W-00000214",
"gesture": "d060b870-15ba-42c9-a932-2d2951087152",
"details": {
"description": "Eeee",
"name": "Bbbb",
"id": 32
},
"type": "homeassistant",
"user": "7a4d5bf9-01b1-413b-bb4d-77728e931dcc",
"updatedAt": 1716378013721,
"createdAt": 1716378013721,
"id": "1a050b25-7fed-4e0e-b5af-792b8b4650de"
}
]

View File

@ -1,6 +1,6 @@
"""Tests for the Knocki event platform."""
from collections.abc import Callable
from collections.abc import Awaitable, Callable
from unittest.mock import AsyncMock
from knocki import Event, EventType, Trigger, TriggerDetails
@ -89,10 +89,39 @@ async def test_adding_runtime_entities(
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]
mock_knocki_client.register_listener.call_args_list[0][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
async def test_removing_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 = [
Trigger.from_dict(trigger)
for trigger in load_json_array_fixture("more_triggers.json", DOMAIN)
]
await setup_integration(hass, mock_config_entry)
assert hass.states.get("event.knc1_w_00000214_aaaa") is not None
assert hass.states.get("event.knc1_w_00000214_bbbb") is not None
remove_trigger_function: Callable[[Event], Awaitable[None]] = (
mock_knocki_client.register_listener.call_args_list[1][0][1]
)
trigger = Trigger.from_dict(load_json_array_fixture("triggers.json", DOMAIN)[0])
mock_knocki_client.get_triggers.return_value = [trigger]
await remove_trigger_function(Event(EventType.DELETED, trigger))
assert hass.states.get("event.knc1_w_00000214_aaaa") is not None
assert hass.states.get("event.knc1_w_00000214_bbbb") is None