1 """Support for Ness D8X/D16X devices."""
3 from collections
import namedtuple
7 from nessclient
import ArmingMode, ArmingState, Client
8 import voluptuous
as vol
11 DEVICE_CLASSES_SCHEMA
as BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
12 BinarySensorDeviceClass,
19 EVENT_HOMEASSISTANT_STOP,
29 _LOGGER = logging.getLogger(__name__)
32 DATA_NESS =
"ness_alarm"
34 CONF_DEVICE_PORT =
"port"
35 CONF_INFER_ARMING_STATE =
"infer_arming_state"
37 CONF_ZONE_NAME =
"name"
38 CONF_ZONE_TYPE =
"type"
40 ATTR_OUTPUT_ID =
"output_id"
41 DEFAULT_SCAN_INTERVAL = datetime.timedelta(minutes=1)
42 DEFAULT_INFER_ARMING_STATE =
False
44 SIGNAL_ZONE_CHANGED =
"ness_alarm.zone_changed"
45 SIGNAL_ARMING_STATE_CHANGED =
"ness_alarm.arming_state_changed"
47 ZoneChangedData = namedtuple(
"ZoneChangedData", [
"zone_id",
"state"])
49 DEFAULT_ZONE_TYPE = BinarySensorDeviceClass.MOTION
50 ZONE_SCHEMA = vol.Schema(
52 vol.Required(CONF_ZONE_NAME): cv.string,
53 vol.Required(CONF_ZONE_ID): cv.positive_int,
55 CONF_ZONE_TYPE, default=DEFAULT_ZONE_TYPE
56 ): BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
60 CONFIG_SCHEMA = vol.Schema(
64 vol.Required(CONF_HOST): cv.string,
65 vol.Required(CONF_DEVICE_PORT): cv.port,
67 CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
68 ): cv.positive_time_period,
69 vol.Optional(CONF_ZONES, default=[]): vol.All(
70 cv.ensure_list, [ZONE_SCHEMA]
73 CONF_INFER_ARMING_STATE, default=DEFAULT_INFER_ARMING_STATE
78 extra=vol.ALLOW_EXTRA,
81 SERVICE_PANIC =
"panic"
84 SERVICE_SCHEMA_PANIC = vol.Schema({vol.Required(ATTR_CODE): cv.string})
85 SERVICE_SCHEMA_AUX = vol.Schema(
87 vol.Required(ATTR_OUTPUT_ID): cv.positive_int,
88 vol.Optional(ATTR_STATE, default=
True): cv.boolean,
93 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
94 """Set up the Ness Alarm platform."""
98 zones = conf[CONF_ZONES]
99 host = conf[CONF_HOST]
100 port = conf[CONF_DEVICE_PORT]
101 scan_interval = conf[CONF_SCAN_INTERVAL]
102 infer_arming_state = conf[CONF_INFER_ARMING_STATE]
107 update_interval=scan_interval.total_seconds(),
108 infer_arming_state=infer_arming_state,
110 hass.data[DATA_NESS] = client
112 async
def _close(event):
115 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _close)
117 async
def _started(event):
119 _LOGGER.debug(
"invoking client keepalive() & update()")
120 hass.loop.create_task(client.keepalive())
121 hass.loop.create_task(client.update())
125 hass.async_create_task(
127 hass, Platform.BINARY_SENSOR, DOMAIN, {CONF_ZONES: zones}, config
130 hass.async_create_task(
134 def on_zone_change(zone_id: int, state: bool):
135 """Receives and propagates zone state updates."""
137 hass, SIGNAL_ZONE_CHANGED,
ZoneChangedData(zone_id=zone_id, state=state)
140 def on_state_change(arming_state: ArmingState, arming_mode: ArmingMode |
None):
141 """Receives and propagates arming state updates."""
143 hass, SIGNAL_ARMING_STATE_CHANGED, arming_state, arming_mode
146 client.on_zone_change(on_zone_change)
147 client.on_state_change(on_state_change)
149 async
def handle_panic(call: ServiceCall) ->
None:
150 await client.panic(call.data[ATTR_CODE])
152 async
def handle_aux(call: ServiceCall) ->
None:
153 await client.aux(call.data[ATTR_OUTPUT_ID], call.data[ATTR_STATE])
155 hass.services.async_register(
156 DOMAIN, SERVICE_PANIC, handle_panic, schema=SERVICE_SCHEMA_PANIC
158 hass.services.async_register(
159 DOMAIN, SERVICE_AUX, handle_aux, schema=SERVICE_SCHEMA_AUX
bool async_setup(HomeAssistant hass, ConfigType config)
None async_load_platform(core.HomeAssistant hass, Platform|str component, str platform, DiscoveryInfoType|None discovered, ConfigType hass_config)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
CALLBACK_TYPE async_at_started(HomeAssistant hass, Callable[[HomeAssistant], Coroutine[Any, Any, None]|None] at_start_cb)