mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Added satel_integra alarm panel and binary sensor platform (#9336)
* Added satel_integra alarm panel and binary sensor platform * Fixed several issues after review: import cleanup, reduced messaging levels to debug, other. * Fixes after review: removed dead code, improved loop, sorted imports. * Changes after review, not yet working * Changes after review - wrapped async code, killed ensure_future, moved async_load_platform into jobs
This commit is contained in:
parent
c44397e257
commit
3996c609b4
@ -161,6 +161,9 @@ omit =
|
|||||||
homeassistant/components/rpi_pfio.py
|
homeassistant/components/rpi_pfio.py
|
||||||
homeassistant/components/*/rpi_pfio.py
|
homeassistant/components/*/rpi_pfio.py
|
||||||
|
|
||||||
|
homeassistant/components/satel_integra.py
|
||||||
|
homeassistant/components/*/satel_integra.py
|
||||||
|
|
||||||
homeassistant/components/scsgate.py
|
homeassistant/components/scsgate.py
|
||||||
homeassistant/components/*/scsgate.py
|
homeassistant/components/*/scsgate.py
|
||||||
|
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
"""
|
||||||
|
Support for Satel Integra alarm, using ETHM module: https://www.satel.pl/en/ .
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/alarm_control_panel.satel_integra/
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import homeassistant.components.alarm_control_panel as alarm
|
||||||
|
from homeassistant.components.satel_integra import (CONF_ARM_HOME_MODE,
|
||||||
|
DATA_SATEL,
|
||||||
|
SIGNAL_PANEL_MESSAGE)
|
||||||
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DEPENDENCIES = ['satel_integra']
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
|
"""Set up for AlarmDecoder alarm panels."""
|
||||||
|
if not discovery_info:
|
||||||
|
return
|
||||||
|
|
||||||
|
device = SatelIntegraAlarmPanel("Alarm Panel",
|
||||||
|
discovery_info.get(CONF_ARM_HOME_MODE))
|
||||||
|
async_add_devices([device])
|
||||||
|
|
||||||
|
|
||||||
|
class SatelIntegraAlarmPanel(alarm.AlarmControlPanel):
|
||||||
|
"""Representation of an AlarmDecoder-based alarm panel."""
|
||||||
|
|
||||||
|
def __init__(self, name, arm_home_mode):
|
||||||
|
"""Initialize the alarm panel."""
|
||||||
|
self._name = name
|
||||||
|
self._state = None
|
||||||
|
self._arm_home_mode = arm_home_mode
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_added_to_hass(self):
|
||||||
|
"""Register callbacks."""
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass, SIGNAL_PANEL_MESSAGE, self._message_callback)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _message_callback(self, message):
|
||||||
|
|
||||||
|
if message != self._state:
|
||||||
|
self._state = message
|
||||||
|
self.async_schedule_update_ha_state()
|
||||||
|
else:
|
||||||
|
_LOGGER.warning("Ignoring alarm status message, same state")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Return the polling state."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def code_format(self):
|
||||||
|
"""Return the regex for code format or None if no code is required."""
|
||||||
|
return '^\\d{4,6}$'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the device."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_alarm_disarm(self, code=None):
|
||||||
|
"""Send disarm command."""
|
||||||
|
if code:
|
||||||
|
yield from self.hass.data[DATA_SATEL].disarm(code)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_alarm_arm_away(self, code=None):
|
||||||
|
"""Send arm away command."""
|
||||||
|
if code:
|
||||||
|
yield from self.hass.data[DATA_SATEL].arm(code)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_alarm_arm_home(self, code=None):
|
||||||
|
"""Send arm home command."""
|
||||||
|
if code:
|
||||||
|
yield from self.hass.data[DATA_SATEL].arm(code,
|
||||||
|
self._arm_home_mode)
|
90
homeassistant/components/binary_sensor/satel_integra.py
Normal file
90
homeassistant/components/binary_sensor/satel_integra.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""
|
||||||
|
Support for Satel Integra zone states- represented as binary sensors.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/binary_sensor.satel_integra/
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
|
from homeassistant.components.satel_integra import (CONF_ZONES,
|
||||||
|
CONF_ZONE_NAME,
|
||||||
|
CONF_ZONE_TYPE,
|
||||||
|
SIGNAL_ZONES_UPDATED)
|
||||||
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
DEPENDENCIES = ['satel_integra']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
|
"""Set up the Satel Integra binary sensor devices."""
|
||||||
|
if not discovery_info:
|
||||||
|
return
|
||||||
|
|
||||||
|
configured_zones = discovery_info[CONF_ZONES]
|
||||||
|
|
||||||
|
devices = []
|
||||||
|
|
||||||
|
for zone_num, device_config_data in configured_zones.items():
|
||||||
|
zone_type = device_config_data[CONF_ZONE_TYPE]
|
||||||
|
zone_name = device_config_data[CONF_ZONE_NAME]
|
||||||
|
device = SatelIntegraBinarySensor(zone_num, zone_name, zone_type)
|
||||||
|
devices.append(device)
|
||||||
|
|
||||||
|
async_add_devices(devices)
|
||||||
|
|
||||||
|
|
||||||
|
class SatelIntegraBinarySensor(BinarySensorDevice):
|
||||||
|
"""Representation of an Satel Integra binary sensor."""
|
||||||
|
|
||||||
|
def __init__(self, zone_number, zone_name, zone_type):
|
||||||
|
"""Initialize the binary_sensor."""
|
||||||
|
self._zone_number = zone_number
|
||||||
|
self._name = zone_name
|
||||||
|
self._zone_type = zone_type
|
||||||
|
self._state = 0
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_added_to_hass(self):
|
||||||
|
"""Register callbacks."""
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass, SIGNAL_ZONES_UPDATED, self._zones_updated)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the entity."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Icon for device by its type."""
|
||||||
|
if self._zone_type == 'smoke':
|
||||||
|
return "mdi:fire"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No polling needed."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return true if sensor is on."""
|
||||||
|
return self._state == 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Return the class of this sensor, from DEVICE_CLASSES."""
|
||||||
|
return self._zone_type
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _zones_updated(self, zones):
|
||||||
|
"""Update the zone's state, if needed."""
|
||||||
|
if self._zone_number in zones \
|
||||||
|
and self._state != zones[self._zone_number]:
|
||||||
|
self._state = zones[self._zone_number]
|
||||||
|
self.async_schedule_update_ha_state()
|
152
homeassistant/components/satel_integra.py
Normal file
152
homeassistant/components/satel_integra.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
Support for Satel Integra devices.
|
||||||
|
|
||||||
|
For more details about this component, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/satel_integra/
|
||||||
|
"""
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.const import (
|
||||||
|
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED, EVENT_HOMEASSISTANT_STOP)
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
|
REQUIREMENTS = ['satel_integra==0.1.0']
|
||||||
|
|
||||||
|
DEFAULT_ALARM_NAME = 'satel_integra'
|
||||||
|
DEFAULT_PORT = 7094
|
||||||
|
DEFAULT_CONF_ARM_HOME_MODE = 1
|
||||||
|
DEFAULT_DEVICE_PARTITION = 1
|
||||||
|
DEFAULT_ZONE_TYPE = 'motion'
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DOMAIN = 'satel_integra'
|
||||||
|
|
||||||
|
DATA_SATEL = 'satel_integra'
|
||||||
|
|
||||||
|
CONF_DEVICE_HOST = 'host'
|
||||||
|
CONF_DEVICE_PORT = 'port'
|
||||||
|
CONF_DEVICE_PARTITION = 'partition'
|
||||||
|
CONF_ARM_HOME_MODE = 'arm_home_mode'
|
||||||
|
CONF_ZONE_NAME = 'name'
|
||||||
|
CONF_ZONE_TYPE = 'type'
|
||||||
|
CONF_ZONES = 'zones'
|
||||||
|
|
||||||
|
ZONES = 'zones'
|
||||||
|
|
||||||
|
SIGNAL_PANEL_MESSAGE = 'satel_integra.panel_message'
|
||||||
|
SIGNAL_PANEL_ARM_AWAY = 'satel_integra.panel_arm_away'
|
||||||
|
SIGNAL_PANEL_ARM_HOME = 'satel_integra.panel_arm_home'
|
||||||
|
SIGNAL_PANEL_DISARM = 'satel_integra.panel_disarm'
|
||||||
|
|
||||||
|
SIGNAL_ZONES_UPDATED = 'satel_integra.zones_updated'
|
||||||
|
|
||||||
|
ZONE_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(CONF_ZONE_NAME): cv.string,
|
||||||
|
vol.Optional(CONF_ZONE_TYPE, default=DEFAULT_ZONE_TYPE): cv.string})
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
vol.Required(CONF_DEVICE_HOST): cv.string,
|
||||||
|
vol.Optional(CONF_DEVICE_PORT, default=DEFAULT_PORT): cv.port,
|
||||||
|
vol.Optional(CONF_DEVICE_PARTITION,
|
||||||
|
default=DEFAULT_DEVICE_PARTITION): cv.positive_int,
|
||||||
|
vol.Optional(CONF_ARM_HOME_MODE,
|
||||||
|
default=DEFAULT_CONF_ARM_HOME_MODE): vol.In([1, 2, 3]),
|
||||||
|
vol.Optional(CONF_ZONES): {vol.Coerce(int): ZONE_SCHEMA},
|
||||||
|
}),
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_setup(hass, config):
|
||||||
|
"""Set up the Satel Integra component."""
|
||||||
|
conf = config.get(DOMAIN)
|
||||||
|
|
||||||
|
zones = conf.get(CONF_ZONES)
|
||||||
|
host = conf.get(CONF_DEVICE_HOST)
|
||||||
|
port = conf.get(CONF_DEVICE_PORT)
|
||||||
|
partition = conf.get(CONF_DEVICE_PARTITION)
|
||||||
|
|
||||||
|
from satel_integra.satel_integra import AsyncSatel, AlarmState
|
||||||
|
|
||||||
|
controller = AsyncSatel(host, port, zones, hass.loop, partition)
|
||||||
|
|
||||||
|
hass.data[DATA_SATEL] = controller
|
||||||
|
|
||||||
|
result = yield from controller.connect()
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _close():
|
||||||
|
controller.close()
|
||||||
|
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _close())
|
||||||
|
|
||||||
|
_LOGGER.debug("Arm home config: %s, mode: %s ",
|
||||||
|
conf,
|
||||||
|
conf.get(CONF_ARM_HOME_MODE))
|
||||||
|
|
||||||
|
task_control_panel = hass.async_add_job(
|
||||||
|
async_load_platform(hass, 'alarm_control_panel', DOMAIN, conf, config))
|
||||||
|
|
||||||
|
task_zones = hass.async_add_job(
|
||||||
|
async_load_platform(hass, 'binary_sensor', DOMAIN,
|
||||||
|
{CONF_ZONES: zones}, config))
|
||||||
|
|
||||||
|
yield from asyncio.wait([task_control_panel, task_zones], loop=hass.loop)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def alarm_status_update_callback(status):
|
||||||
|
"""Send status update received from alarm to home assistant."""
|
||||||
|
_LOGGER.debug("Alarm status callback, status: %s", status)
|
||||||
|
hass_alarm_status = STATE_ALARM_DISARMED
|
||||||
|
|
||||||
|
if status == AlarmState.ARMED_MODE0:
|
||||||
|
hass_alarm_status = STATE_ALARM_ARMED_AWAY
|
||||||
|
|
||||||
|
elif status in [
|
||||||
|
AlarmState.ARMED_MODE0,
|
||||||
|
AlarmState.ARMED_MODE1,
|
||||||
|
AlarmState.ARMED_MODE2,
|
||||||
|
AlarmState.ARMED_MODE3
|
||||||
|
]:
|
||||||
|
hass_alarm_status = STATE_ALARM_ARMED_HOME
|
||||||
|
|
||||||
|
elif status in [AlarmState.TRIGGERED, AlarmState.TRIGGERED_FIRE]:
|
||||||
|
hass_alarm_status = STATE_ALARM_TRIGGERED
|
||||||
|
|
||||||
|
elif status == AlarmState.DISARMED:
|
||||||
|
hass_alarm_status = STATE_ALARM_DISARMED
|
||||||
|
|
||||||
|
_LOGGER.debug("Sending hass_alarm_status: %s...", hass_alarm_status)
|
||||||
|
async_dispatcher_send(hass, SIGNAL_PANEL_MESSAGE, hass_alarm_status)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def zones_update_callback(status):
|
||||||
|
"""Update zone objects as per notification from the alarm."""
|
||||||
|
_LOGGER.debug("Zones callback , status: %s", status)
|
||||||
|
async_dispatcher_send(hass, SIGNAL_ZONES_UPDATED, status[ZONES])
|
||||||
|
|
||||||
|
# Create a task instead of adding a tracking job, since this task will
|
||||||
|
# run until the connection to satel_integra is closed.
|
||||||
|
hass.loop.create_task(controller.keep_alive())
|
||||||
|
hass.loop.create_task(
|
||||||
|
controller.monitor_status(
|
||||||
|
alarm_status_update_callback,
|
||||||
|
zones_update_callback)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
@ -883,6 +883,9 @@ rxv==0.4.0
|
|||||||
# homeassistant.components.media_player.samsungtv
|
# homeassistant.components.media_player.samsungtv
|
||||||
samsungctl==0.6.0
|
samsungctl==0.6.0
|
||||||
|
|
||||||
|
# homeassistant.components.satel_integra
|
||||||
|
satel_integra==0.1.0
|
||||||
|
|
||||||
# homeassistant.components.sensor.deutsche_bahn
|
# homeassistant.components.sensor.deutsche_bahn
|
||||||
schiene==0.18
|
schiene==0.18
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user