Add ness alarm control panel using nessclient (#18463)
* Add ness alarm control panel using nessclient * indenting * . * Remove availability functionality, will improve and add back in another PR * Use call_count * lint * lint * Review changes * Lint * Bump nessclient to 0.9.8 * Bump nessclient to 0.9.9 * Remove from .coveragerc
This commit is contained in:
parent
61d5b3028d
commit
5aa2bd81cf
6 changed files with 566 additions and 0 deletions
121
homeassistant/components/ness_alarm.py
Normal file
121
homeassistant/components/ness_alarm.py
Normal file
|
@ -0,0 +1,121 @@
|
|||
"""
|
||||
Support for Ness D8X/D16X devices.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/ness_alarm/
|
||||
"""
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.binary_sensor import DEVICE_CLASSES
|
||||
from homeassistant.const import 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 = ['nessclient==0.9.9']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'ness_alarm'
|
||||
DATA_NESS = 'ness_alarm'
|
||||
|
||||
CONF_DEVICE_HOST = 'host'
|
||||
CONF_DEVICE_PORT = 'port'
|
||||
CONF_ZONES = 'zones'
|
||||
CONF_ZONE_NAME = 'name'
|
||||
CONF_ZONE_TYPE = 'type'
|
||||
CONF_ZONE_ID = 'id'
|
||||
ATTR_CODE = 'code'
|
||||
ATTR_OUTPUT_ID = 'output_id'
|
||||
ATTR_STATE = 'state'
|
||||
DEFAULT_ZONES = []
|
||||
|
||||
SIGNAL_ZONE_CHANGED = 'ness_alarm.zone_changed'
|
||||
SIGNAL_ARMING_STATE_CHANGED = 'ness_alarm.arming_state_changed'
|
||||
|
||||
ZoneChangedData = namedtuple('ZoneChangedData', ['zone_id', 'state'])
|
||||
|
||||
DEFAULT_ZONE_TYPE = 'motion'
|
||||
ZONE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ZONE_NAME): cv.string,
|
||||
vol.Required(CONF_ZONE_ID): cv.positive_int,
|
||||
vol.Optional(CONF_ZONE_TYPE, default=DEFAULT_ZONE_TYPE):
|
||||
vol.In(DEVICE_CLASSES)})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_DEVICE_HOST): cv.string,
|
||||
vol.Required(CONF_DEVICE_PORT): cv.port,
|
||||
vol.Optional(CONF_ZONES, default=DEFAULT_ZONES):
|
||||
vol.All(cv.ensure_list, [ZONE_SCHEMA]),
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
SERVICE_PANIC = 'panic'
|
||||
SERVICE_AUX = 'aux'
|
||||
|
||||
SERVICE_SCHEMA_PANIC = vol.Schema({
|
||||
vol.Required(ATTR_CODE): cv.string,
|
||||
})
|
||||
SERVICE_SCHEMA_AUX = vol.Schema({
|
||||
vol.Required(ATTR_OUTPUT_ID): cv.positive_int,
|
||||
vol.Optional(ATTR_STATE, default=True): cv.boolean,
|
||||
})
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the Ness Alarm platform."""
|
||||
from nessclient import Client, ArmingState
|
||||
conf = config[DOMAIN]
|
||||
|
||||
zones = conf[CONF_ZONES]
|
||||
host = conf[CONF_DEVICE_HOST]
|
||||
port = conf[CONF_DEVICE_PORT]
|
||||
|
||||
client = Client(host=host, port=port, loop=hass.loop)
|
||||
hass.data[DATA_NESS] = client
|
||||
|
||||
async def _close(event):
|
||||
await client.close()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _close)
|
||||
|
||||
hass.async_create_task(
|
||||
async_load_platform(hass, 'binary_sensor', DOMAIN, {CONF_ZONES: zones},
|
||||
config))
|
||||
hass.async_create_task(
|
||||
async_load_platform(hass, 'alarm_control_panel', DOMAIN, {}, config))
|
||||
|
||||
def on_zone_change(zone_id: int, state: bool):
|
||||
"""Receives and propagates zone state updates."""
|
||||
async_dispatcher_send(hass, SIGNAL_ZONE_CHANGED, ZoneChangedData(
|
||||
zone_id=zone_id,
|
||||
state=state,
|
||||
))
|
||||
|
||||
def on_state_change(arming_state: ArmingState):
|
||||
"""Receives and propagates arming state updates."""
|
||||
async_dispatcher_send(hass, SIGNAL_ARMING_STATE_CHANGED, arming_state)
|
||||
|
||||
client.on_zone_change(on_zone_change)
|
||||
client.on_state_change(on_state_change)
|
||||
|
||||
# Force update for current arming status and current zone states
|
||||
hass.loop.create_task(client.keepalive())
|
||||
hass.loop.create_task(client.update())
|
||||
|
||||
async def handle_panic(call):
|
||||
await client.panic(call.data[ATTR_CODE])
|
||||
|
||||
async def handle_aux(call):
|
||||
await client.aux(call.data[ATTR_OUTPUT_ID], call.data[ATTR_STATE])
|
||||
|
||||
hass.services.async_register(DOMAIN, SERVICE_PANIC, handle_panic,
|
||||
schema=SERVICE_SCHEMA_PANIC)
|
||||
hass.services.async_register(DOMAIN, SERVICE_AUX, handle_aux,
|
||||
schema=SERVICE_SCHEMA_AUX)
|
||||
|
||||
return True
|
Loading…
Add table
Add a link
Reference in a new issue