Clean up SimpliSafe entity inheritance structure (#58063)
* Migrate SimpliSafe to new web-based authentication * Ensure we're storing data correctly * Re-organize SimpliSafe device structure * Constants * More work * Code review
This commit is contained in:
parent
c7ff6eb5ee
commit
2ff356393c
5 changed files with 57 additions and 72 deletions
|
@ -7,8 +7,7 @@ from datetime import timedelta
|
||||||
from typing import TYPE_CHECKING, cast
|
from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
from simplipy import API
|
from simplipy import API
|
||||||
from simplipy.device.sensor.v2 import SensorV2
|
from simplipy.device import Device
|
||||||
from simplipy.device.sensor.v3 import SensorV3
|
|
||||||
from simplipy.errors import (
|
from simplipy.errors import (
|
||||||
EndpointUnavailableError,
|
EndpointUnavailableError,
|
||||||
InvalidCredentialsError,
|
InvalidCredentialsError,
|
||||||
|
@ -62,6 +61,8 @@ from .const import (
|
||||||
|
|
||||||
EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION"
|
EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION"
|
||||||
|
|
||||||
|
DEFAULT_ENTITY_MODEL = "alarm_control_panel"
|
||||||
|
DEFAULT_ENTITY_NAME = "Alarm Control Panel"
|
||||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
|
DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
|
||||||
DEFAULT_SOCKET_MIN_RETRY = 15
|
DEFAULT_SOCKET_MIN_RETRY = 15
|
||||||
|
|
||||||
|
@ -159,7 +160,7 @@ async def async_register_base_station(
|
||||||
device_registry = await dr.async_get_registry(hass)
|
device_registry = await dr.async_get_registry(hass)
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
config_entry_id=entry.entry_id,
|
config_entry_id=entry.entry_id,
|
||||||
identifiers={(DOMAIN, system.serial)},
|
identifiers={(DOMAIN, system.system_id)},
|
||||||
manufacturer="SimpliSafe",
|
manufacturer="SimpliSafe",
|
||||||
model=system.version,
|
model=system.version,
|
||||||
name=system.address,
|
name=system.address,
|
||||||
|
@ -424,29 +425,34 @@ class SimpliSafeEntity(CoordinatorEntity):
|
||||||
self,
|
self,
|
||||||
simplisafe: SimpliSafe,
|
simplisafe: SimpliSafe,
|
||||||
system: SystemV2 | SystemV3,
|
system: SystemV2 | SystemV3,
|
||||||
name: str,
|
|
||||||
*,
|
*,
|
||||||
serial: str | None = None,
|
device: Device | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
assert simplisafe.coordinator
|
assert simplisafe.coordinator
|
||||||
super().__init__(simplisafe.coordinator)
|
super().__init__(simplisafe.coordinator)
|
||||||
|
|
||||||
if serial:
|
if device:
|
||||||
self._serial = serial
|
model = device.type.name
|
||||||
|
device_name = device.name
|
||||||
|
serial = device.serial
|
||||||
else:
|
else:
|
||||||
self._serial = system.serial
|
model = DEFAULT_ENTITY_MODEL
|
||||||
|
device_name = DEFAULT_ENTITY_NAME
|
||||||
|
serial = system.serial
|
||||||
|
|
||||||
self._attr_extra_state_attributes = {ATTR_SYSTEM_ID: system.system_id}
|
self._attr_extra_state_attributes = {ATTR_SYSTEM_ID: system.system_id}
|
||||||
self._attr_device_info = {
|
self._attr_device_info = {
|
||||||
"identifiers": {(DOMAIN, system.system_id)},
|
"identifiers": {(DOMAIN, serial)},
|
||||||
"manufacturer": "SimpliSafe",
|
"manufacturer": "SimpliSafe",
|
||||||
"model": str(system.version),
|
"model": model,
|
||||||
"name": name,
|
"name": device_name,
|
||||||
"via_device": (DOMAIN, system.serial),
|
"via_device": (DOMAIN, system.system_id),
|
||||||
}
|
}
|
||||||
self._attr_name = f"{system.address} {name}"
|
|
||||||
self._attr_unique_id = self._serial
|
self._attr_name = f"{system.address} {device_name} {' '.join([w.title() for w in model.split('_')])}"
|
||||||
|
self._attr_unique_id = serial
|
||||||
|
self._device = device
|
||||||
self._online = True
|
self._online = True
|
||||||
self._simplisafe = simplisafe
|
self._simplisafe = simplisafe
|
||||||
self._system = system
|
self._system = system
|
||||||
|
@ -481,29 +487,3 @@ class SimpliSafeEntity(CoordinatorEntity):
|
||||||
def async_update_from_rest_api(self) -> None:
|
def async_update_from_rest_api(self) -> None:
|
||||||
"""Update the entity with the provided REST API data."""
|
"""Update the entity with the provided REST API data."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class SimpliSafeBaseSensor(SimpliSafeEntity):
|
|
||||||
"""Define a SimpliSafe base (binary) sensor."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
simplisafe: SimpliSafe,
|
|
||||||
system: SystemV2 | SystemV3,
|
|
||||||
sensor: SensorV2 | SensorV3,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize."""
|
|
||||||
super().__init__(simplisafe, system, sensor.name, serial=sensor.serial)
|
|
||||||
|
|
||||||
self._attr_device_info = {
|
|
||||||
"identifiers": {(DOMAIN, sensor.serial)},
|
|
||||||
"manufacturer": "SimpliSafe",
|
|
||||||
"model": sensor.type.name,
|
|
||||||
"name": sensor.name,
|
|
||||||
"via_device": (DOMAIN, system.serial),
|
|
||||||
}
|
|
||||||
|
|
||||||
human_friendly_name = " ".join([w.title() for w in sensor.type.name.split("_")])
|
|
||||||
self._attr_name = f"{super().name} {human_friendly_name}"
|
|
||||||
|
|
||||||
self._sensor = sensor
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
||||||
|
|
||||||
def __init__(self, simplisafe: SimpliSafe, system: SystemV2 | SystemV3) -> None:
|
def __init__(self, simplisafe: SimpliSafe, system: SystemV2 | SystemV3) -> None:
|
||||||
"""Initialize the SimpliSafe alarm."""
|
"""Initialize the SimpliSafe alarm."""
|
||||||
super().__init__(simplisafe, system, "Alarm Control Panel")
|
super().__init__(simplisafe, system)
|
||||||
|
|
||||||
if code := self._simplisafe.entry.options.get(CONF_CODE):
|
if code := self._simplisafe.entry.options.get(CONF_CODE):
|
||||||
if code.isdigit():
|
if code.isdigit():
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from simplipy.device import DeviceTypes
|
from simplipy.device import DeviceTypes
|
||||||
from simplipy.device.sensor.v2 import SensorV2
|
|
||||||
from simplipy.device.sensor.v3 import SensorV3
|
from simplipy.device.sensor.v3 import SensorV3
|
||||||
from simplipy.system.v2 import SystemV2
|
|
||||||
from simplipy.system.v3 import SystemV3
|
from simplipy.system.v3 import SystemV3
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
|
@ -22,7 +20,7 @@ from homeassistant.const import ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import SimpliSafe, SimpliSafeBaseSensor
|
from . import SimpliSafe, SimpliSafeEntity
|
||||||
from .const import DATA_CLIENT, DOMAIN, LOGGER
|
from .const import DATA_CLIENT, DOMAIN, LOGGER
|
||||||
|
|
||||||
SUPPORTED_BATTERY_SENSOR_TYPES = [
|
SUPPORTED_BATTERY_SENSOR_TYPES = [
|
||||||
|
@ -77,45 +75,45 @@ async def async_setup_entry(
|
||||||
async_add_entities(sensors)
|
async_add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
class TriggeredBinarySensor(SimpliSafeBaseSensor, BinarySensorEntity):
|
class TriggeredBinarySensor(SimpliSafeEntity, BinarySensorEntity):
|
||||||
"""Define a binary sensor related to whether an entity has been triggered."""
|
"""Define a binary sensor related to whether an entity has been triggered."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
simplisafe: SimpliSafe,
|
simplisafe: SimpliSafe,
|
||||||
system: SystemV2 | SystemV3,
|
system: SystemV3,
|
||||||
sensor: SensorV2 | SensorV3,
|
sensor: SensorV3,
|
||||||
device_class: str,
|
device_class: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__(simplisafe, system, sensor)
|
super().__init__(simplisafe, system, device=sensor)
|
||||||
|
|
||||||
self._attr_device_class = device_class
|
self._attr_device_class = device_class
|
||||||
|
self._device: SensorV3
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_from_rest_api(self) -> None:
|
def async_update_from_rest_api(self) -> None:
|
||||||
"""Update the entity with the provided REST API data."""
|
"""Update the entity with the provided REST API data."""
|
||||||
self._attr_is_on = self._sensor.triggered
|
self._attr_is_on = self._device.triggered
|
||||||
|
|
||||||
|
|
||||||
class BatteryBinarySensor(SimpliSafeBaseSensor, BinarySensorEntity):
|
class BatteryBinarySensor(SimpliSafeEntity, BinarySensorEntity):
|
||||||
"""Define a SimpliSafe battery binary sensor entity."""
|
"""Define a SimpliSafe battery binary sensor entity."""
|
||||||
|
|
||||||
_attr_device_class = DEVICE_CLASS_BATTERY
|
_attr_device_class = DEVICE_CLASS_BATTERY
|
||||||
_attr_entity_category = ENTITY_CATEGORY_DIAGNOSTIC
|
_attr_entity_category = ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, simplisafe: SimpliSafe, system: SystemV3, sensor: SensorV3
|
||||||
simplisafe: SimpliSafe,
|
|
||||||
system: SystemV2 | SystemV3,
|
|
||||||
sensor: SensorV2 | SensorV3,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__(simplisafe, system, sensor)
|
super().__init__(simplisafe, system, device=sensor)
|
||||||
|
|
||||||
|
self._attr_name = f"{super().name} Battery"
|
||||||
self._attr_unique_id = f"{super().unique_id}-battery"
|
self._attr_unique_id = f"{super().unique_id}-battery"
|
||||||
|
self._device: SensorV3
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_from_rest_api(self) -> None:
|
def async_update_from_rest_api(self) -> None:
|
||||||
"""Update the entity with the provided REST API data."""
|
"""Update the entity with the provided REST API data."""
|
||||||
self._attr_is_on = self._sensor.low_battery
|
self._attr_is_on = self._device.low_battery
|
||||||
|
|
|
@ -42,16 +42,16 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
||||||
|
|
||||||
def __init__(self, simplisafe: SimpliSafe, system: SystemV3, lock: Lock) -> None:
|
def __init__(self, simplisafe: SimpliSafe, system: SystemV3, lock: Lock) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__(simplisafe, system, lock.name, serial=lock.serial)
|
super().__init__(simplisafe, system, device=lock)
|
||||||
|
|
||||||
self._lock = lock
|
self._device: Lock
|
||||||
|
|
||||||
async def async_lock(self, **kwargs: Any) -> None:
|
async def async_lock(self, **kwargs: Any) -> None:
|
||||||
"""Lock the lock."""
|
"""Lock the lock."""
|
||||||
try:
|
try:
|
||||||
await self._lock.async_lock()
|
await self._device.async_lock()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
LOGGER.error('Error while locking "%s": %s', self._lock.name, err)
|
LOGGER.error('Error while locking "%s": %s', self._device.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._attr_is_locked = True
|
self._attr_is_locked = True
|
||||||
|
@ -60,9 +60,9 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
||||||
async def async_unlock(self, **kwargs: Any) -> None:
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
"""Unlock the lock."""
|
"""Unlock the lock."""
|
||||||
try:
|
try:
|
||||||
await self._lock.async_unlock()
|
await self._device.async_unlock()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
LOGGER.error('Error while unlocking "%s": %s', self._lock.name, err)
|
LOGGER.error('Error while unlocking "%s": %s', self._device.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._attr_is_locked = False
|
self._attr_is_locked = False
|
||||||
|
@ -73,10 +73,10 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
||||||
"""Update the entity with the provided REST API data."""
|
"""Update the entity with the provided REST API data."""
|
||||||
self._attr_extra_state_attributes.update(
|
self._attr_extra_state_attributes.update(
|
||||||
{
|
{
|
||||||
ATTR_LOCK_LOW_BATTERY: self._lock.lock_low_battery,
|
ATTR_LOCK_LOW_BATTERY: self._device.lock_low_battery,
|
||||||
ATTR_PIN_PAD_LOW_BATTERY: self._lock.pin_pad_low_battery,
|
ATTR_PIN_PAD_LOW_BATTERY: self._device.pin_pad_low_battery,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self._attr_is_jammed = self._lock.state == LockStates.jammed
|
self._attr_is_jammed = self._device.state == LockStates.jammed
|
||||||
self._attr_is_locked = self._lock.state == LockStates.locked
|
self._attr_is_locked = self._device.state == LockStates.locked
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
"""Support for SimpliSafe freeze sensor."""
|
"""Support for SimpliSafe freeze sensor."""
|
||||||
from typing import TYPE_CHECKING
|
from __future__ import annotations
|
||||||
|
|
||||||
from simplipy.device import DeviceTypes
|
from simplipy.device import DeviceTypes
|
||||||
from simplipy.device.sensor.v3 import SensorV3
|
from simplipy.device.sensor.v3 import SensorV3
|
||||||
|
from simplipy.system.v3 import SystemV3
|
||||||
|
|
||||||
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
|
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
@ -10,7 +11,7 @@ from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_FAHRENHEIT
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import SimpliSafeBaseSensor
|
from . import SimpliSafe, SimpliSafeEntity
|
||||||
from .const import DATA_CLIENT, DOMAIN, LOGGER
|
from .const import DATA_CLIENT, DOMAIN, LOGGER
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,16 +34,22 @@ async def async_setup_entry(
|
||||||
async_add_entities(sensors)
|
async_add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
class SimplisafeFreezeSensor(SimpliSafeBaseSensor, SensorEntity):
|
class SimplisafeFreezeSensor(SimpliSafeEntity, SensorEntity):
|
||||||
"""Define a SimpliSafe freeze sensor entity."""
|
"""Define a SimpliSafe freeze sensor entity."""
|
||||||
|
|
||||||
_attr_device_class = DEVICE_CLASS_TEMPERATURE
|
_attr_device_class = DEVICE_CLASS_TEMPERATURE
|
||||||
_attr_native_unit_of_measurement = TEMP_FAHRENHEIT
|
_attr_native_unit_of_measurement = TEMP_FAHRENHEIT
|
||||||
_attr_state_class = STATE_CLASS_MEASUREMENT
|
_attr_state_class = STATE_CLASS_MEASUREMENT
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, simplisafe: SimpliSafe, system: SystemV3, sensor: SensorV3
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
super().__init__(simplisafe, system, device=sensor)
|
||||||
|
|
||||||
|
self._device: SensorV3
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_from_rest_api(self) -> None:
|
def async_update_from_rest_api(self) -> None:
|
||||||
"""Update the entity with the provided REST API data."""
|
"""Update the entity with the provided REST API data."""
|
||||||
if TYPE_CHECKING:
|
self._attr_native_value = self._device.temperature
|
||||||
assert isinstance(self._sensor, SensorV3)
|
|
||||||
self._attr_native_value = self._sensor.temperature
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue