1
mirror of https://github.com/home-assistant/core synced 2024-07-15 09:42:11 +02:00

Add new locks automatically to tedee integration (#107372)

* remove removed locks

* move duplicated code to function

* remove entities by removing device

* add new locks automatically

* add locks from coordinator

* remove other PR stuff

* add pullspring lock to test for coverage

* requested changes
This commit is contained in:
Josef Zweck 2024-01-06 16:02:07 +01:00 committed by GitHub
parent d6aaaf1f1a
commit 7385da626e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 2 deletions

View File

@ -66,6 +66,17 @@ async def async_setup_entry(
]
)
def _async_add_new_lock(lock_id: int) -> None:
lock = coordinator.data[lock_id]
async_add_entities(
[
TedeeBinarySensorEntity(lock, coordinator, entity_description)
for entity_description in ENTITIES
]
)
coordinator.new_lock_callbacks.append(_async_add_new_lock)
class TedeeBinarySensorEntity(TedeeDescriptionEntity, BinarySensorEntity):
"""Tedee sensor entity."""

View File

@ -50,6 +50,8 @@ class TedeeApiCoordinator(DataUpdateCoordinator[dict[int, TedeeLock]]):
)
self._next_get_locks = time.time()
self._current_locks: set[int] = set()
self.new_lock_callbacks: list[Callable[[int], None]] = []
@property
def bridge(self) -> TedeeBridge:
@ -82,6 +84,15 @@ class TedeeApiCoordinator(DataUpdateCoordinator[dict[int, TedeeLock]]):
", ".join(map(str, self.tedee_client.locks_dict.keys())),
)
if not self._current_locks:
self._current_locks = set(self.tedee_client.locks_dict.keys())
if new_locks := set(self.tedee_client.locks_dict.keys()) - self._current_locks:
_LOGGER.debug("New locks found: %s", ", ".join(map(str, new_locks)))
for lock_id in new_locks:
for callback in self.new_lock_callbacks:
callback(lock_id)
return self.tedee_client.locks_dict
async def _async_update(self, update_fn: Callable[[], Awaitable[None]]) -> None:

View File

@ -29,6 +29,15 @@ async def async_setup_entry(
else:
entities.append(TedeeLockEntity(lock, coordinator))
def _async_add_new_lock(lock_id: int) -> None:
lock = coordinator.data[lock_id]
if lock.is_enabled_pullspring:
async_add_entities([TedeeLockWithLatchEntity(lock, coordinator)])
else:
async_add_entities([TedeeLockEntity(lock, coordinator)])
coordinator.new_lock_callbacks.append(_async_add_new_lock)
async_add_entities(entities)

View File

@ -62,6 +62,17 @@ async def async_setup_entry(
]
)
def _async_add_new_lock(lock_id: int) -> None:
lock = coordinator.data[lock_id]
async_add_entities(
[
TedeeSensorEntity(lock, coordinator, entity_description)
for entity_description in ENTITIES
]
)
coordinator.new_lock_callbacks.append(_async_add_new_lock)
class TedeeSensorEntity(TedeeDescriptionEntity, SensorEntity):
"""Tedee sensor entity."""

View File

@ -128,4 +128,4 @@
'last_updated': <ANY>,
'state': 'off',
})
# ---
# ---

View File

@ -26,4 +26,4 @@
'sw_version': None,
'via_device_id': None,
})
# ---
# ---

View File

@ -1,13 +1,18 @@
"""Tests for the Tedee Binary Sensors."""
from datetime import timedelta
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pytedee_async import TedeeLock
import pytest
from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import async_fire_time_changed
pytestmark = pytest.mark.usefixtures("init_integration")
BINARY_SENSORS = (
@ -32,3 +37,25 @@ async def test_binary_sensors(
entry = entity_registry.async_get(state.entity_id)
assert entry
assert entry == snapshot(name=f"entry-{key}")
async def test_new_binary_sensors(
hass: HomeAssistant,
mock_tedee: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure binary sensors for new lock are added automatically."""
for key in BINARY_SENSORS:
state = hass.states.get(f"binary_sensor.lock_4e5f_{key}")
assert state is None
mock_tedee.locks_dict[666666] = TedeeLock("Lock-4E5F", 666666, 2)
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done()
for key in BINARY_SENSORS:
state = hass.states.get(f"binary_sensor.lock_4e5f_{key}")
assert state

View File

@ -3,6 +3,7 @@ from datetime import timedelta
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pytedee_async import TedeeLock
from pytedee_async.exception import (
TedeeClientException,
TedeeDataUpdateException,
@ -207,3 +208,31 @@ async def test_update_failed(
state = hass.states.get("lock.lock_1a2b")
assert state is not None
assert state.state == STATE_UNAVAILABLE
async def test_new_lock(
hass: HomeAssistant,
mock_tedee: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure new lock is added automatically."""
state = hass.states.get("lock.lock_4e5f")
assert state is None
mock_tedee.locks_dict[666666] = TedeeLock("Lock-4E5F", 666666, 2)
mock_tedee.locks_dict[777777] = TedeeLock(
"Lock-6G7H",
777777,
4,
is_enabled_pullspring=True,
)
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get("lock.lock_4e5f")
assert state
state = hass.states.get("lock.lock_6g7h")
assert state

View File

@ -1,14 +1,19 @@
"""Tests for the Tedee Sensors."""
from datetime import timedelta
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pytedee_async import TedeeLock
import pytest
from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import async_fire_time_changed
pytestmark = pytest.mark.usefixtures("init_integration")
@ -34,3 +39,25 @@ async def test_sensors(
assert entry
assert entry.device_id
assert entry == snapshot(name=f"entry-{key}")
async def test_new_sensors(
hass: HomeAssistant,
mock_tedee: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure sensors for new lock are added automatically."""
for key in SENSORS:
state = hass.states.get(f"sensor.lock_4e5f_{key}")
assert state is None
mock_tedee.locks_dict[666666] = TedeeLock("Lock-4E5F", 666666, 2)
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done()
for key in SENSORS:
state = hass.states.get(f"sensor.lock_4e5f_{key}")
assert state