Create base entity for SimpliSafe

This commit is contained in:
Aaron Bach 2019-11-09 15:41:02 -07:00 committed by Martin Hjelmare
parent a39cac765e
commit 179a2eb187
5 changed files with 85 additions and 59 deletions

View File

@ -22,7 +22,11 @@ from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
) )
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.service import verify_domain_control from homeassistant.helpers.service import verify_domain_control
@ -240,3 +244,73 @@ class SimpliSafe:
tasks = [self._update_system(system) for system in self.systems.values()] tasks = [self._update_system(system) for system in self.systems.values()]
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
class SimpliSafeEntity(Entity):
"""Define a base SimpliSafe entity."""
def __init__(self, system, name, *, serial=None):
"""Initialize."""
self._async_unsub_dispatcher_connect = None
self._attrs = {ATTR_SYSTEM_ID: system.system_id}
self._name = name
self._online = True
self._system = system
if serial:
self._serial = serial
else:
self._serial = system.serial
@property
def available(self):
"""Return whether the entity is available."""
# We can easily detect if the V3 system is offline, but no simple check exists
# for the V2 system. Therefore, we mark the entity as available if:
# 1. We can verify that the system is online (assuming True if we can't)
# 2. We can verify that the entity is online
system_offline = self._system.version == 3 and self._system.offline
return not system_offline and self._online
@property
def device_info(self):
"""Return device registry information for this entity."""
return {
"identifiers": {(DOMAIN, self._system.system_id)},
"manufacturer": "SimpliSafe",
"model": self._system.version,
"name": self._name,
"via_device": (DOMAIN, self._system.serial),
}
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attrs
@property
def name(self):
"""Return the name of the entity."""
return f"{self._system.address} {self._name}"
@property
def unique_id(self):
"""Return the unique ID of the entity."""
return self._serial
async def async_added_to_hass(self):
"""Register callbacks."""
@callback
def update():
"""Update the state."""
self.async_schedule_update_ha_state(True)
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
self.hass, TOPIC_UPDATE, update
)
async def async_will_remove_from_hass(self) -> None:
"""Disconnect dispatcher listener when removed."""
if self._async_unsub_dispatcher_connect:
self._async_unsub_dispatcher_connect()

View File

@ -2,7 +2,7 @@
import logging import logging
import re import re
from simplipy.sensor import SensorTypes from simplipy.entity import EntityTypes
from simplipy.system import SystemStates from simplipy.system import SystemStates
from homeassistant.components.alarm_control_panel import ( from homeassistant.components.alarm_control_panel import (
@ -16,11 +16,10 @@ from homeassistant.const import (
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED, STATE_ALARM_DISARMED,
) )
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util.dt import utc_from_timestamp from homeassistant.util.dt import utc_from_timestamp
from .const import DATA_CLIENT, DOMAIN, TOPIC_UPDATE from . import SimpliSafeEntity
from .const import DATA_CLIENT, DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -33,7 +32,6 @@ ATTR_LAST_EVENT_SENSOR_TYPE = "last_event_sensor_type"
ATTR_LAST_EVENT_TIMESTAMP = "last_event_timestamp" ATTR_LAST_EVENT_TIMESTAMP = "last_event_timestamp"
ATTR_LAST_EVENT_TYPE = "last_event_type" ATTR_LAST_EVENT_TYPE = "last_event_type"
ATTR_RF_JAMMING = "rf_jamming" ATTR_RF_JAMMING = "rf_jamming"
ATTR_SYSTEM_ID = "system_id"
ATTR_WALL_POWER_LEVEL = "wall_power_level" ATTR_WALL_POWER_LEVEL = "wall_power_level"
ATTR_WIFI_STRENGTH = "wifi_strength" ATTR_WIFI_STRENGTH = "wifi_strength"
@ -55,18 +53,16 @@ async def async_setup_entry(hass, entry, async_add_entities):
) )
class SimpliSafeAlarm(AlarmControlPanel): class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanel):
"""Representation of a SimpliSafe alarm.""" """Representation of a SimpliSafe alarm."""
def __init__(self, simplisafe, system, code): def __init__(self, simplisafe, system, code):
"""Initialize the SimpliSafe alarm.""" """Initialize the SimpliSafe alarm."""
self._async_unsub_dispatcher_connect = None super().__init__(system, "Alarm Control Panel")
self._attrs = {ATTR_SYSTEM_ID: system.system_id}
self._changed_by = None self._changed_by = None
self._code = code self._code = code
self._simplisafe = simplisafe self._simplisafe = simplisafe
self._state = None self._state = None
self._system = system
# Some properties only exist for V2 or V3 systems: # Some properties only exist for V2 or V3 systems:
for prop in ( for prop in (
@ -93,39 +89,11 @@ class SimpliSafeAlarm(AlarmControlPanel):
return FORMAT_NUMBER return FORMAT_NUMBER
return FORMAT_TEXT return FORMAT_TEXT
@property
def device_info(self):
"""Return device registry information for this entity."""
return {
"identifiers": {(DOMAIN, self._system.system_id)},
"manufacturer": "SimpliSafe",
"model": self._system.version,
# The name should become more dynamic once we deduce a way to
# get various other sensors from SimpliSafe in a reliable manner:
"name": "Keypad",
"via_device": (DOMAIN, self._system.serial),
}
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attrs
@property
def name(self):
"""Return the name of the entity."""
return self._system.address
@property @property
def state(self): def state(self):
"""Return the state of the entity.""" """Return the state of the entity."""
return self._state return self._state
@property
def unique_id(self):
"""Return the unique ID of the entity."""
return self._system.system_id
def _validate_code(self, code, state): def _validate_code(self, code, state):
"""Validate given code.""" """Validate given code."""
check = self._code is None or code == self._code check = self._code is None or code == self._code
@ -133,18 +101,6 @@ class SimpliSafeAlarm(AlarmControlPanel):
_LOGGER.warning("Wrong code entered for %s", state) _LOGGER.warning("Wrong code entered for %s", state)
return check return check
async def async_added_to_hass(self):
"""Register callbacks."""
@callback
def update():
"""Update the state."""
self.async_schedule_update_ha_state(True)
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
self.hass, TOPIC_UPDATE, update
)
async def async_alarm_disarm(self, code=None): async def async_alarm_disarm(self, code=None):
"""Send disarm command.""" """Send disarm command."""
if not self._validate_code(code, "disarming"): if not self._validate_code(code, "disarming"):
@ -174,6 +130,7 @@ class SimpliSafeAlarm(AlarmControlPanel):
self._changed_by = event_data["pinName"] self._changed_by = event_data["pinName"]
if self._system.state == SystemStates.error: if self._system.state == SystemStates.error:
self._online = False
return return
if self._system.state == SystemStates.off: if self._system.state == SystemStates.off:
@ -195,15 +152,10 @@ class SimpliSafeAlarm(AlarmControlPanel):
ATTR_ALARM_ACTIVE: self._system.alarm_going_off, ATTR_ALARM_ACTIVE: self._system.alarm_going_off,
ATTR_LAST_EVENT_INFO: last_event["info"], ATTR_LAST_EVENT_INFO: last_event["info"],
ATTR_LAST_EVENT_SENSOR_NAME: last_event["sensorName"], ATTR_LAST_EVENT_SENSOR_NAME: last_event["sensorName"],
ATTR_LAST_EVENT_SENSOR_TYPE: SensorTypes(last_event["sensorType"]).name, ATTR_LAST_EVENT_SENSOR_TYPE: EntityTypes(last_event["sensorType"]).name,
ATTR_LAST_EVENT_TIMESTAMP: utc_from_timestamp( ATTR_LAST_EVENT_TIMESTAMP: utc_from_timestamp(
last_event["eventTimestamp"] last_event["eventTimestamp"]
), ),
ATTR_LAST_EVENT_TYPE: last_event["eventType"], ATTR_LAST_EVENT_TYPE: last_event["eventType"],
} }
) )
async def async_will_remove_from_hass(self) -> None:
"""Disconnect dispatcher listener when removed."""
if self._async_unsub_dispatcher_connect:
self._async_unsub_dispatcher_connect()

View File

@ -4,7 +4,7 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/simplisafe", "documentation": "https://www.home-assistant.io/integrations/simplisafe",
"requirements": [ "requirements": [
"simplisafe-python==5.0.1" "simplisafe-python==5.1.0"
], ],
"dependencies": [], "dependencies": [],
"codeowners": [ "codeowners": [

View File

@ -1769,7 +1769,7 @@ shodan==1.19.0
simplepush==1.1.4 simplepush==1.1.4
# homeassistant.components.simplisafe # homeassistant.components.simplisafe
simplisafe-python==5.0.1 simplisafe-python==5.1.0
# homeassistant.components.sisyphus # homeassistant.components.sisyphus
sisyphus-control==2.2.1 sisyphus-control==2.2.1

View File

@ -546,7 +546,7 @@ rxv==0.6.0
samsungctl[websocket]==0.7.1 samsungctl[websocket]==0.7.1
# homeassistant.components.simplisafe # homeassistant.components.simplisafe
simplisafe-python==5.0.1 simplisafe-python==5.1.0
# homeassistant.components.sleepiq # homeassistant.components.sleepiq
sleepyq==0.7 sleepyq==0.7