forked from fernac03/JFL_ACTIVE
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalarm_control_panel.py
247 lines (222 loc) · 8.56 KB
/
alarm_control_panel.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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
"""Support for JFL Active20 alarm control panels. """
from __future__ import annotations
import voluptuous as vol
import logging
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_CODE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
CONF_ALT_NIGHT_MODE,
CONF_AUTO_BYPASS,
CONF_PARTITION,
CONF_CODE_REQUIRED,
CONF_CODE_ARM_REQUIRED,
DATA_AD,
DEFAULT_ARM_OPTIONS,
DOMAIN,
CONF_MODELO,
OPTIONS_ARM,
SIGNAL_PANEL_MESSAGE,
)
_LOGGER = logging.getLogger(__name__)
SERVICE_ALARM_TOGGLE_CHIME = "alarm_toggle_chime"
SERVICE_ALARM_KEYPRESS = "alarm_keypress"
ATTR_KEYPRESS = "keypress"
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up for JFL Active20 alarm panels."""
options = entry.options
arm_options = options.get(OPTIONS_ARM, DEFAULT_ARM_OPTIONS)
client = hass.data[DOMAIN][entry.entry_id][DATA_AD]
entity = AlarmDecoderAlarmPanel(
client=client,
auto_bypass=arm_options[CONF_AUTO_BYPASS],
code_arm_required=arm_options[CONF_CODE_ARM_REQUIRED],
code_required=arm_options[CONF_CODE_REQUIRED],
alt_night_mode=arm_options[CONF_ALT_NIGHT_MODE],
)
async_add_entities([entity])
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_ALARM_TOGGLE_CHIME,
{
vol.Required(ATTR_CODE): cv.string,
},
"alarm_toggle_chime",
)
platform.async_register_entity_service(
SERVICE_ALARM_KEYPRESS,
{
vol.Required(ATTR_KEYPRESS): cv.string,
},
"alarm_keypress",
)
class AlarmDecoderAlarmPanel(AlarmControlPanelEntity):
"""Representation of an JFL Active20 alarm panel."""
_attr_name = "Alarm Panel"
_attr_should_poll = False
_attr_code_format = CodeFormat.NUMBER
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
| AlarmControlPanelEntityFeature.ARM_NIGHT
)
def __init__(self, client, auto_bypass, code_arm_required, alt_night_mode,code_required):
"""Initialize the alarm panel."""
self._client = client
self._code = code_required
self._auto_bypass = auto_bypass
self._attr_code_arm_required = code_arm_required
self._alt_night_mode = alt_night_mode
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
self.async_on_remove(
async_dispatcher_connect(
self.hass, SIGNAL_PANEL_MESSAGE, self._message_callback
)
)
def _message_callback(self, message):
"""Handle received messages."""
if message.alarm_sounding or message.fire_alarm:
self._attr_state = STATE_ALARM_TRIGGERED
elif message.armed_away:
self._attr_state = STATE_ALARM_ARMED_AWAY
_LOGGER.warning("mensagem armed_AWAY")
elif message.armed_home:
self._attr_state = STATE_ALARM_ARMED_HOME
_LOGGER.warning("mensagem armed_home")
elif message.armed_night:
self._attr_state = STATE_ALARM_ARMED_NIGHT
_LOGGER.warning("mensagem armed_night")
else:
self._attr_state = STATE_ALARM_DISARMED
_LOGGER.warning("mensagem disarmed")
self._attr_extra_state_attributes = {
"ac_power": message.ac_power,
"alarm_event_occurred": message.alarm_event_occurred,
"backlight_on": message.backlight_on,
"battery_low": message.battery_low,
"check_zone": message.check_zone,
"chime": message.chime_on,
"entry_delay_off": message.entry_delay_off,
"programming_mode": message.programming_mode,
"ready": message.ready,
"zone_bypassed": message.zone_bypassed,
}
self.schedule_update_ha_state()
def checksum(self,dados):
checksum = 0
for n in dados:
checksum ^= n
return checksum
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
if not self._validate_code(code, STATE_ALARM_DISARMED):
return
if CONF_PARTITION:
message = b'\xb3\x36\x02\x00\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
message = b'\xB3\x36\x02\x01\x00\x00\x00'
check = slef.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
else:
message = b'\xb3\x36\x02\x00\x00\x00\x00'
check = self.checksum(message)
self._attr_state = STATE_ALARM_DISARMED
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if self.code_arm_required and not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
return
if CONF_PARTITION:
message = b'\xb3\x36\x01\x00\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
message = b'\xb3\x36\x01\x01\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
else:
message = b'\xb3\x36\x01\x00\x00\x00\x00'
check = self.checksum(message)
self._attr_state = STATE_ALARM_ARMED_AWAY
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
self._client.put(message)
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
if self.code_arm_required and not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
if CONF_PARTITION:
message = b'\xb3\x36\x01\x01\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
else:
message = b'\xb3\x36\x01\x00\x00\x00\x00'
check = self.checksum(message)
self._attr_state = STATE_ALARM_ARMED_HOME
message += check.to_bytes(1,'big')
self._client.put(message)
def alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
if self.code_arm_required and not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
if CONF_PARTITION:
message = b'\xb3\x36\x01\x00\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
message = b'\xb3\x36\x01\x01\x00\x00\x00'
check = self.checksum(message)
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
else:
message = b'\xb3\x36\x01\x00\x00\x00\x00'
check = self.checksum(message)
self._attr_state = STATE_ALARM_ARMED_NIGHT
message += check.to_bytes(1,'big')
self._client.put(bytes(message))
def alarm_toggle_chime(self, code=None):
"""Send toggle chime command."""
if code:
self._client.send(f"{code!s}9")
def alarm_keypress(self, keypress):
"""Send custom keypresses."""
if keypress:
self._client.send(keypress)
def _validate_code(self, code, state):
"""Validate given code."""
if self._code is None:
return True
if isinstance(self._code, str):
alarm_code = self._code
else:
alarm_code = self._code.render(
parse_result=False, from_state=self._state, to_state=state
)
check = not alarm_code or code == alarm_code
if not check:
_LOGGER.warning("Invalid code given for %s", state)
return check