show metadata for locks

This commit is contained in:
Ole Bittner 2024-07-08 22:09:55 +02:00
parent 3cb164cae0
commit a22192846c
Signed by: obittner
GPG Key ID: 51C6E3916445D6B2
6 changed files with 182 additions and 8 deletions

View File

@ -38,7 +38,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
api.set_update_token_callback(__update_entry)
hass.data[DOMAIN][username] = {}
hass.data[DOMAIN][username]["api"] = api
@ -48,4 +47,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator.async_config_entry_first_refresh()
await hass.config_entries.async_forward_entry_setup(entry, "button")
await hass.config_entries.async_forward_entry_setup(entry, "sensor")
await hass.config_entries.async_forward_entry_setup(entry, "binary_sensor")
return True

View File

@ -0,0 +1,59 @@
from __future__ import annotations
from datetime import datetime
import logging
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .reos_api import ReosApi, ReosLockModel
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None:
coordinator = hass.data[DOMAIN][config_entry.data["username"]]["coordinator"]
async_add_entities(ReosDoorIsFavorite(lock, coordinator) for _, lock in coordinator.data.items())
class BinarySensorBase(CoordinatorEntity, BinarySensorEntity):
def update_value(self) -> None:
pass
def __format_id(self, name: str) -> str:
return name.lower().replace(' ', '_')
def __init__(self, model: ReosLockModel, coordinator, name: str) -> None:
super().__init__(coordinator, context=model.lock_id)
self._model = model
self.idx = self._model.lock_id
self._attr_unique_id = f"reos_lock_{self._model.lock_id}_{self.__format_id(name)}"
self._attr_name = f"{self._model.display} {name}"
self.update_value()
@callback
def _handle_coordinator_update(self) -> None:
self._model = self.coordinator.data[self.idx]
self.update_value()
self.async_write_ha_state()
@property
def device_info(self) -> DeviceInfo | None:
return DeviceInfo(
identifiers={(DOMAIN, self.idx)},
)
class ReosDoorIsFavorite(BinarySensorBase):
def update_value(self) -> None:
self._attr_is_on = self._model.is_favorite
def __init__(self, model: ReosLockModel, coordinator) -> None:
super().__init__(model, coordinator, "Is Favorite")

View File

@ -25,15 +25,15 @@ class ReosDoorButton(CoordinatorEntity, ButtonEntity):
super().__init__(coordinator, context=model.lock_id)
self._model = model
self.idx = self._model.lock_id
self._attr_unique_id = f"reos_lock_{self._model.lock_id}"
self._attr_name = self._model.display
self._attr_unique_id = f"reos_lock_{self._model.lock_id}_buzzer"
self._attr_name = f"{self._model.display} Buzzer"
self._attr_device_class = "door"
self._attr_icon = "mdi:door"
@callback
def _handle_coordinator_update(self) -> None:
self._model = self.coordinator.data[self.idx]
_LOGGER.info(f"_handle_coordinator_update for {self.idx}")
_LOGGER.info("_handle_coordinator_update for %s", self.idx)
self.async_write_ha_state()
def press(self, **kwargs) -> None:
@ -41,4 +41,7 @@ class ReosDoorButton(CoordinatorEntity, ButtonEntity):
@property
def device_info(self) -> DeviceInfo | None:
return None
return DeviceInfo(
identifiers={(DOMAIN, self.idx)},
name=self._model.display
)

View File

@ -23,7 +23,7 @@ class ReosCoordinator(DataUpdateCoordinator):
hass,
_LOGGER,
name="Reos Locks",
update_interval=timedelta(hours=24),
update_interval=timedelta(hours=6),
)
self.api = api

View File

@ -1,4 +1,6 @@
from homeassistant.core import HomeAssistant
from datetime import datetime
import dateutil.parser
import aiohttp
import asyncio
import logging
@ -72,6 +74,12 @@ class ReosApi:
_json = await response.json()
return _json["access_token"], _json["refresh_token"]
def __parse_datetime(self, dt: datetime) -> datetime | None:
if dt is not None:
return dateutil.parser.parse(str(dt))
else:
return None
async def open_lock(self, lock_id: int) -> None:
async with await self.__get_session() as session:
await session.post(f"{PROTOCOL}://{self.host}{LOCK_OPEN_ENDPOINT}", json={"lockId": lock_id})
@ -104,19 +112,27 @@ class ReosApi:
_attr["title"],
_attr["display_title"],
_attr["is_favorite"],
self
self,
updated_at=self.__parse_datetime(_attr["updated_at"]),
created_at=self.__parse_datetime(_attr["created_at"]),
available_from=self.__parse_datetime(_attr["available_from"]),
available_to=self.__parse_datetime(_attr["available_to"])
)
locks.append(_lock)
return locks
class ReosLockModel:
def __init__(self, id: int, name: str, display: str, is_favorite: bool, api: ReosApi) -> None:
def __init__(self, id: int, name: str, display: str, is_favorite: bool, api: ReosApi, available_from: datetime = None, available_to: datetime = None, created_at: datetime = None, updated_at: datetime = None) -> None:
self._id = id
self.name = name
self.display = display
self._api = api
self.is_favorite = is_favorite
self.available_from = available_from
self.available_to = available_to
self.created_at = created_at
self.updated_at = updated_at
@property
def lock_id(self) -> int:

View File

@ -0,0 +1,95 @@
from __future__ import annotations
from datetime import datetime
import logging
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .reos_api import ReosApi, ReosLockModel
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None:
coordinator = hass.data[DOMAIN][config_entry.data["username"]]["coordinator"]
async_add_entities(ReosDoorUpdatedAt(lock, coordinator) for _, lock in coordinator.data.items())
async_add_entities(ReosDoorCreatedAt(lock, coordinator) for _, lock in coordinator.data.items())
async_add_entities(ReosDoorAvailableFrom(lock, coordinator) for _, lock in coordinator.data.items())
async_add_entities(ReosDoorAvailableTo(lock, coordinator) for _, lock in coordinator.data.items())
class SensorBase(CoordinatorEntity, SensorEntity):
def update_value(self) -> None:
pass
def __format_id(self, name: str) -> str:
return name.lower().replace(' ', '_')
def __init__(self, model: ReosLockModel, coordinator, name: str) -> None:
super().__init__(coordinator, context=model.lock_id)
self._model = model
self.idx = self._model.lock_id
self._attr_unique_id = f"reos_lock_{self._model.lock_id}_{self.__format_id(name)}"
self._attr_name = f"{self._model.display} {name}"
self.update_value()
@callback
def _handle_coordinator_update(self) -> None:
self._model = self.coordinator.data[self.idx]
self.update_value()
self.async_write_ha_state()
@property
def device_info(self) -> DeviceInfo | None:
return DeviceInfo(
identifiers={(DOMAIN, self.idx)},
)
class TimestampSensorBase(SensorBase):
def __init__(self, model: ReosLockModel, coordinator, name: str) -> None:
super().__init__(model, coordinator, name)
self._attr_device_class = SensorDeviceClass.TIMESTAMP
class ReosDoorUpdatedAt(TimestampSensorBase):
def update_value(self) -> None:
self._attr_native_value = self._model.updated_at
def __init__(self, model: ReosLockModel, coordinator) -> None:
super().__init__(model, coordinator, "Updated At")
class ReosDoorCreatedAt(TimestampSensorBase):
def update_value(self) -> None:
self._attr_native_value = self._model.created_at
def __init__(self, model: ReosLockModel, coordinator) -> None:
super().__init__(model, coordinator, "Created At")
class ReosDoorAvailableFrom(TimestampSensorBase):
def update_value(self) -> None:
self._attr_native_value = self._model.available_from
def __init__(self, model: ReosLockModel, coordinator) -> None:
super().__init__(model, coordinator, "Available From")
class ReosDoorAvailableTo(TimestampSensorBase):
def update_value(self) -> None:
self._attr_native_value = self._model.available_to
def __init__(self, model: ReosLockModel, coordinator) -> None:
super().__init__(model, coordinator, "Available To")