-
-
Notifications
You must be signed in to change notification settings - Fork 31k
/
__init__.py
161 lines (128 loc) · 5.24 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""Support for AlarmDecoder devices."""
from datetime import timedelta
import logging
from adext import AdExt
from alarmdecoder.devices import SerialDevice, SocketDevice
from alarmdecoder.util import NoDeviceError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
CONF_PROTOCOL,
EVENT_HOMEASSISTANT_STOP,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.event import async_call_later
from .const import (
CONF_DEVICE_BAUD,
CONF_DEVICE_PATH,
DATA_AD,
DATA_REMOVE_STOP_LISTENER,
DATA_REMOVE_UPDATE_LISTENER,
DATA_RESTART,
DOMAIN,
PROTOCOL_SERIAL,
PROTOCOL_SOCKET,
SIGNAL_PANEL_MESSAGE,
SIGNAL_REL_MESSAGE,
SIGNAL_RFX_MESSAGE,
SIGNAL_ZONE_FAULT,
SIGNAL_ZONE_RESTORE,
)
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [
Platform.ALARM_CONTROL_PANEL,
Platform.BINARY_SENSOR,
Platform.SENSOR,
]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up AlarmDecoder config flow."""
undo_listener = entry.add_update_listener(_update_listener)
ad_connection = entry.data
protocol = ad_connection[CONF_PROTOCOL]
def stop_alarmdecoder(event):
"""Handle the shutdown of AlarmDecoder."""
if not hass.data.get(DOMAIN):
return
_LOGGER.debug("Shutting down alarmdecoder")
hass.data[DOMAIN][entry.entry_id][DATA_RESTART] = False
controller.close()
async def open_connection(now=None):
"""Open a connection to AlarmDecoder."""
try:
await hass.async_add_executor_job(controller.open, baud)
except NoDeviceError:
_LOGGER.debug("Failed to connect. Retrying in 5 seconds")
async_call_later(hass, timedelta(seconds=5), open_connection)
return
_LOGGER.debug("Established a connection with the alarmdecoder")
hass.data[DOMAIN][entry.entry_id][DATA_RESTART] = True
def handle_closed_connection(event):
"""Restart after unexpected loss of connection."""
if not hass.data[DOMAIN][entry.entry_id][DATA_RESTART]:
return
hass.data[DOMAIN][entry.entry_id][DATA_RESTART] = False
_LOGGER.warning("AlarmDecoder unexpectedly lost connection")
hass.add_job(open_connection)
def handle_message(sender, message):
"""Handle message from AlarmDecoder."""
dispatcher_send(hass, SIGNAL_PANEL_MESSAGE, message)
def handle_rfx_message(sender, message):
"""Handle RFX message from AlarmDecoder."""
dispatcher_send(hass, SIGNAL_RFX_MESSAGE, message)
def zone_fault_callback(sender, zone):
"""Handle zone fault from AlarmDecoder."""
dispatcher_send(hass, SIGNAL_ZONE_FAULT, zone)
def zone_restore_callback(sender, zone):
"""Handle zone restore from AlarmDecoder."""
dispatcher_send(hass, SIGNAL_ZONE_RESTORE, zone)
def handle_rel_message(sender, message):
"""Handle relay or zone expander message from AlarmDecoder."""
dispatcher_send(hass, SIGNAL_REL_MESSAGE, message)
baud = ad_connection.get(CONF_DEVICE_BAUD)
if protocol == PROTOCOL_SOCKET:
host = ad_connection[CONF_HOST]
port = ad_connection[CONF_PORT]
controller = AdExt(SocketDevice(interface=(host, port)))
if protocol == PROTOCOL_SERIAL:
path = ad_connection[CONF_DEVICE_PATH]
controller = AdExt(SerialDevice(interface=path))
controller.on_message += handle_message
controller.on_rfx_message += handle_rfx_message
controller.on_zone_fault += zone_fault_callback
controller.on_zone_restore += zone_restore_callback
controller.on_close += handle_closed_connection
controller.on_expander_message += handle_rel_message
remove_stop_listener = hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, stop_alarmdecoder
)
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = {
DATA_AD: controller,
DATA_REMOVE_UPDATE_LISTENER: undo_listener,
DATA_REMOVE_STOP_LISTENER: remove_stop_listener,
DATA_RESTART: False,
}
await open_connection()
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a AlarmDecoder entry."""
hass.data[DOMAIN][entry.entry_id][DATA_RESTART] = False
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if not unload_ok:
return False
hass.data[DOMAIN][entry.entry_id][DATA_REMOVE_UPDATE_LISTENER]()
hass.data[DOMAIN][entry.entry_id][DATA_REMOVE_STOP_LISTENER]()
await hass.async_add_executor_job(hass.data[DOMAIN][entry.entry_id][DATA_AD].close)
if hass.data[DOMAIN][entry.entry_id]:
hass.data[DOMAIN].pop(entry.entry_id)
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
return True
async def _update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle options update."""
_LOGGER.debug("AlarmDecoder options updated: %s", entry.as_dict()["options"])
await hass.config_entries.async_reload(entry.entry_id)