diff --git a/.coveragerc b/.coveragerc index 2bbbb93cda5..5f820665db9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -213,7 +213,9 @@ omit = homeassistant/components/doorbird/entity.py homeassistant/components/doorbird/util.py homeassistant/components/dormakaba_dkey/__init__.py + homeassistant/components/dormakaba_dkey/entity.py homeassistant/components/dormakaba_dkey/lock.py + homeassistant/components/dormakaba_dkey/sensor.py homeassistant/components/dovado/* homeassistant/components/downloader/* homeassistant/components/dsmr_reader/__init__.py diff --git a/homeassistant/components/dormakaba_dkey/__init__.py b/homeassistant/components/dormakaba_dkey/__init__.py index 8162fb68bb7..1f2d83a2582 100644 --- a/homeassistant/components/dormakaba_dkey/__init__.py +++ b/homeassistant/components/dormakaba_dkey/__init__.py @@ -19,7 +19,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda from .const import CONF_ASSOCIATION_DATA, DOMAIN, UPDATE_SECONDS from .models import DormakabaDkeyData -PLATFORMS: list[Platform] = [Platform.LOCK] +PLATFORMS: list[Platform] = [Platform.LOCK, Platform.SENSOR] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/dormakaba_dkey/entity.py b/homeassistant/components/dormakaba_dkey/entity.py new file mode 100644 index 00000000000..9ec2720d1e8 --- /dev/null +++ b/homeassistant/components/dormakaba_dkey/entity.py @@ -0,0 +1,56 @@ +"""Dormakaba dKey integration base entity.""" +from __future__ import annotations + +import abc + +from py_dormakaba_dkey import DKEYLock +from py_dormakaba_dkey.commands import Notifications + +from homeassistant.core import callback +from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + + +class DormakabaDkeyEntity(CoordinatorEntity[DataUpdateCoordinator[None]]): + """Dormakaba dKey base entity.""" + + _attr_has_entity_name = True + + def __init__( + self, coordinator: DataUpdateCoordinator[None], lock: DKEYLock + ) -> None: + """Initialize a Dormakaba dKey entity.""" + super().__init__(coordinator) + self._lock = lock + self._attr_device_info = DeviceInfo( + name=lock.device_info.device_name or lock.device_info.device_id, + model="MTL 9291", + sw_version=lock.device_info.sw_version, + connections={(dr.CONNECTION_BLUETOOTH, lock.address)}, + ) + self._async_update_attrs() + + @abc.abstractmethod + @callback + def _async_update_attrs(self) -> None: + """Handle updating _attr values.""" + + @callback + def _handle_coordinator_update(self) -> None: + """Handle data update.""" + self._async_update_attrs() + self.async_write_ha_state() + + @callback + def _handle_state_update(self, update: Notifications) -> None: + """Handle data update.""" + self.coordinator.async_set_updated_data(None) + + async def async_added_to_hass(self) -> None: + """Register callbacks.""" + self.async_on_remove(self._lock.register_callback(self._handle_state_update)) + return await super().async_added_to_hass() diff --git a/homeassistant/components/dormakaba_dkey/lock.py b/homeassistant/components/dormakaba_dkey/lock.py index dffebdd6bc8..e238c4e143b 100644 --- a/homeassistant/components/dormakaba_dkey/lock.py +++ b/homeassistant/components/dormakaba_dkey/lock.py @@ -4,20 +4,16 @@ from __future__ import annotations from typing import Any from py_dormakaba_dkey import DKEYLock -from py_dormakaba_dkey.commands import Notifications, UnlockStatus +from py_dormakaba_dkey.commands import UnlockStatus from homeassistant.components.lock import LockEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import device_registry as dr -from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, - DataUpdateCoordinator, -) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN +from .entity import DormakabaDkeyEntity from .models import DormakabaDkeyData @@ -31,7 +27,7 @@ async def async_setup_entry( async_add_entities([DormakabaDkeyLock(data.coordinator, data.lock)]) -class DormakabaDkeyLock(CoordinatorEntity[DataUpdateCoordinator[None]], LockEntity): +class DormakabaDkeyLock(DormakabaDkeyEntity, LockEntity): """Representation of Dormakaba dKey lock.""" _attr_has_entity_name = True @@ -40,16 +36,8 @@ class DormakabaDkeyLock(CoordinatorEntity[DataUpdateCoordinator[None]], LockEnti self, coordinator: DataUpdateCoordinator[None], lock: DKEYLock ) -> None: """Initialize a Dormakaba dKey lock.""" - super().__init__(coordinator) - self._lock = lock self._attr_unique_id = lock.address - self._attr_device_info = DeviceInfo( - name=lock.device_info.device_name or lock.device_info.device_id, - model="MTL 9291", - sw_version=lock.device_info.sw_version, - connections={(dr.CONNECTION_BLUETOOTH, lock.address)}, - ) - self._async_update_attrs() + super().__init__(coordinator, lock) @callback def _async_update_attrs(self) -> None: @@ -66,19 +54,3 @@ class DormakabaDkeyLock(CoordinatorEntity[DataUpdateCoordinator[None]], LockEnti async def async_unlock(self, **kwargs: Any) -> None: """Unlock the lock.""" await self._lock.unlock() - - @callback - def _handle_coordinator_update(self) -> None: - """Handle data update.""" - self._async_update_attrs() - self.async_write_ha_state() - - @callback - def _handle_state_update(self, update: Notifications) -> None: - """Handle data update.""" - self.coordinator.async_set_updated_data(None) - - async def async_added_to_hass(self) -> None: - """Register callbacks.""" - self.async_on_remove(self._lock.register_callback(self._handle_state_update)) - return await super().async_added_to_hass() diff --git a/homeassistant/components/dormakaba_dkey/sensor.py b/homeassistant/components/dormakaba_dkey/sensor.py new file mode 100644 index 00000000000..8234b41c43a --- /dev/null +++ b/homeassistant/components/dormakaba_dkey/sensor.py @@ -0,0 +1,65 @@ +"""Dormakaba dKey integration sensor platform.""" +from __future__ import annotations + +from py_dormakaba_dkey import DKEYLock + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import PERCENTAGE +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + +from .const import DOMAIN +from .entity import DormakabaDkeyEntity +from .models import DormakabaDkeyData + +BINARY_SENSOR_DESCRIPTIONS = ( + SensorEntityDescription( + key="battery_level", + name="Battery", + device_class=SensorDeviceClass.BATTERY, + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the lock platform for Dormakaba dKey.""" + data: DormakabaDkeyData = hass.data[DOMAIN][entry.entry_id] + async_add_entities( + DormakabaDkeySensor(data.coordinator, data.lock, description) + for description in BINARY_SENSOR_DESCRIPTIONS + ) + + +class DormakabaDkeySensor(DormakabaDkeyEntity, SensorEntity): + """Dormakaba dKey sensor.""" + + _attr_has_entity_name = True + + def __init__( + self, + coordinator: DataUpdateCoordinator[None], + lock: DKEYLock, + description: SensorEntityDescription, + ) -> None: + """Initialize a Dormakaba dKey binary sensor.""" + self.entity_description = description + self._attr_unique_id = f"{lock.address}_{description.key}" + super().__init__(coordinator, lock) + + @callback + def _async_update_attrs(self) -> None: + """Handle updating _attr values.""" + self._attr_native_value = getattr(self._lock, self.entity_description.key)