bosch-alarm-mode2 0.0.0.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bosch_alarm_mode2-0.0.0.dev0/PKG-INFO +11 -0
- bosch_alarm_mode2-0.0.0.dev0/bosch_alarm_mode2/__init__.py +3 -0
- bosch_alarm_mode2-0.0.0.dev0/bosch_alarm_mode2/connection.py +66 -0
- bosch_alarm_mode2-0.0.0.dev0/bosch_alarm_mode2/const.py +176 -0
- bosch_alarm_mode2-0.0.0.dev0/bosch_alarm_mode2/history.py +736 -0
- bosch_alarm_mode2-0.0.0.dev0/bosch_alarm_mode2/panel.py +540 -0
- bosch_alarm_mode2-0.0.0.dev0/pyproject.toml +12 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: bosch-alarm-mode2
|
|
3
|
+
Version: 0.0.0.dev0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Michael Grigoriev
|
|
6
|
+
Author-email: mag@luminal.org
|
|
7
|
+
Requires-Python: >=3.9,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from .const import *
|
|
5
|
+
|
|
6
|
+
LOG = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
class Connection(asyncio.Protocol):
|
|
9
|
+
def __init__(self, passcode, on_status_update, on_disconnect):
|
|
10
|
+
self._passcode = passcode
|
|
11
|
+
self._on_status_update = on_status_update
|
|
12
|
+
self._on_disconnect = on_disconnect
|
|
13
|
+
self._transport = None
|
|
14
|
+
self._buffer = bytearray()
|
|
15
|
+
self._pending = asyncio.Queue()
|
|
16
|
+
|
|
17
|
+
def connection_made(self, transport):
|
|
18
|
+
self._transport = transport
|
|
19
|
+
|
|
20
|
+
def connection_lost(self, exc):
|
|
21
|
+
LOG.info("Connection terminated.")
|
|
22
|
+
self._on_disconnect()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def data_received(self, data):
|
|
26
|
+
LOG.debug("<< %s", data)
|
|
27
|
+
self._buffer += data
|
|
28
|
+
self._consume_buffer()
|
|
29
|
+
|
|
30
|
+
def send_command(self, code, data = bytearray()) -> asyncio.Future:
|
|
31
|
+
request = bytearray(b'\x01') # protocol version
|
|
32
|
+
request.append(len(data) + 1)
|
|
33
|
+
request.append(code)
|
|
34
|
+
request.extend(data)
|
|
35
|
+
response = asyncio.get_running_loop().create_future()
|
|
36
|
+
self._pending.put_nowait(response)
|
|
37
|
+
LOG.debug(">> %s", bytes(request))
|
|
38
|
+
self._transport.write(request)
|
|
39
|
+
return response
|
|
40
|
+
|
|
41
|
+
def close(self):
|
|
42
|
+
if self._transport:
|
|
43
|
+
self._transport.abort()
|
|
44
|
+
self._transport = None
|
|
45
|
+
|
|
46
|
+
def _consume_buffer(self):
|
|
47
|
+
while self._buffer:
|
|
48
|
+
msg_len = 0
|
|
49
|
+
if self._buffer[0] == 0x01:
|
|
50
|
+
msg_len = self._buffer[1] + 2
|
|
51
|
+
if len(self._buffer) < msg_len: break
|
|
52
|
+
self._process_response(self._buffer[2:msg_len])
|
|
53
|
+
elif self._buffer[0] == 0x02:
|
|
54
|
+
msg_len = int.from_bytes(self._buffer[1:3], 'big') + 3
|
|
55
|
+
if len(self._buffer) < msg_len: break
|
|
56
|
+
self._on_status_update(self._buffer[3:msg_len])
|
|
57
|
+
else:
|
|
58
|
+
raise RuntimeError('unknown protocol ' + str(self._buffer))
|
|
59
|
+
self._buffer = self._buffer[msg_len:]
|
|
60
|
+
|
|
61
|
+
def _process_response(self, data):
|
|
62
|
+
response = self._pending.get_nowait()
|
|
63
|
+
if data[0] == 0xFC: response.set_result(None)
|
|
64
|
+
elif data[0] == 0xFD: response.set_exception(Exception("NACK: %s" % ERROR[data[1]]))
|
|
65
|
+
elif data[0] == 0xFE: response.set_result(data[1:])
|
|
66
|
+
else: response.set_exception(Exception("unexpected response code:", data))
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
ERROR = {
|
|
2
|
+
0x00: "Non-specific error",
|
|
3
|
+
0x01: "Checksum failure (UDP connections only)",
|
|
4
|
+
0x02: "Invalid size / length",
|
|
5
|
+
0x03: "Invalid command",
|
|
6
|
+
0x04: "Invalid interface state",
|
|
7
|
+
0x05: "Data out of range",
|
|
8
|
+
0x06: "No authority",
|
|
9
|
+
0x07: "Unsupported command",
|
|
10
|
+
0x08: "Cannot arm panel",
|
|
11
|
+
0x09: "Invalid Remote ID",
|
|
12
|
+
0x0A: "Invalid License",
|
|
13
|
+
0x0B: "Invalid Magic Number",
|
|
14
|
+
0x0C: "Expired License",
|
|
15
|
+
0x0D: "Expired Magic Number",
|
|
16
|
+
0x0E: "Unsupported Format Version",
|
|
17
|
+
0x11: "Firmware Update in Progress",
|
|
18
|
+
0x12: "Incompatible Firmware Version",
|
|
19
|
+
0x13: "All Points Not Configured",
|
|
20
|
+
0x20: "Execution Function No Errors",
|
|
21
|
+
0x21: "Execution Function Invalid Area",
|
|
22
|
+
0x22: "Execution Function Invalid Command",
|
|
23
|
+
0x23: "Execution Function Not Authenticated",
|
|
24
|
+
0x24: "Execution Function Invalid User",
|
|
25
|
+
0x40: "Execution Function Parameter Incorrect",
|
|
26
|
+
0x41: "Execution Function Sequence Wrong",
|
|
27
|
+
0x42: "Execution Function Invalid Configuration Request",
|
|
28
|
+
0x43: "Execution Function Invalid Size",
|
|
29
|
+
0x44: "Execution Function Time Out",
|
|
30
|
+
0xDF: "RF Request Failed",
|
|
31
|
+
0xE0: "No RF device with that RFID",
|
|
32
|
+
0xE1: "Bad RFID. Not proper format",
|
|
33
|
+
0xE2: "Too many RF devices for this panel",
|
|
34
|
+
0xE3: "Duplicate RFID",
|
|
35
|
+
0xE4: "Duplicate access card",
|
|
36
|
+
0xE5: "Bad access card data",
|
|
37
|
+
0xE6: "Bad language choice",
|
|
38
|
+
0xE7: "Bad supervision mode selection",
|
|
39
|
+
0xE8: "Bad enable/disable choice",
|
|
40
|
+
0xE9: "Bad Month",
|
|
41
|
+
0xEA: "Bad Day",
|
|
42
|
+
0xEB: "Bad Hour",
|
|
43
|
+
0xEC: "Bad Minute",
|
|
44
|
+
0xED: "Bad Time edit choice",
|
|
45
|
+
0xEF: "Bad Remote Enable",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
PANEL_MODEL = {
|
|
49
|
+
0x20: "Solution 2000",
|
|
50
|
+
0x21: "Solution 3000",
|
|
51
|
+
0x22: "AMAX 2100",
|
|
52
|
+
0x23: "AMAX 3000",
|
|
53
|
+
0x24: "AMAX 4000",
|
|
54
|
+
0x79: "D7412GV4",
|
|
55
|
+
0x84: "D9412GV4",
|
|
56
|
+
0xA0: "B4512 (US1B)",
|
|
57
|
+
0xA4: "B5512 (US1B)",
|
|
58
|
+
0xA6: "B8512G (US1A)",
|
|
59
|
+
0xA7: "B9512G (US1A)",
|
|
60
|
+
0xA8: "B3512 (US1B)",
|
|
61
|
+
0xA9: "B6512 (US1B)",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
PANEL_HISTORY_LEN = {
|
|
65
|
+
0x20: 0x08,
|
|
66
|
+
0x21: 0x08,
|
|
67
|
+
0x22: 0x08,
|
|
68
|
+
0x23: 0x08,
|
|
69
|
+
0x24: 0x08,
|
|
70
|
+
0x79: 0x10,
|
|
71
|
+
0x84: 0x10,
|
|
72
|
+
0xA0: 0x18,
|
|
73
|
+
0xA4: 0x18,
|
|
74
|
+
0xA6: 0x20,
|
|
75
|
+
0xA7: 0x20,
|
|
76
|
+
0xA8: 0x18,
|
|
77
|
+
0xA9: 0x18,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
AREA_STATUS_UNKNOWN = 0x00
|
|
81
|
+
AREA_STATUS_DISARMED = 0x04
|
|
82
|
+
AREA_STATUS_ARMING = [0x07, 0x08, 0x0D]
|
|
83
|
+
AREA_STATUS_PENDING = [0x05, 0x06, 0x0E]
|
|
84
|
+
AREA_STATUS_PART_ARMED = [0x02, 0x03]
|
|
85
|
+
AREA_STATUS_ALL_ARMED = [0x01, 0x09, 0x0C]
|
|
86
|
+
AREA_STATUS_ARMED = AREA_STATUS_ALL_ARMED + AREA_STATUS_PART_ARMED
|
|
87
|
+
|
|
88
|
+
AREA_STATUS = {
|
|
89
|
+
0x00: "Unknown",
|
|
90
|
+
0x01: "All On / Away Armed",
|
|
91
|
+
0x02: "Part On Instant",
|
|
92
|
+
0x03: "Part On Delay / Stay Armed",
|
|
93
|
+
0x04: "Disarmed",
|
|
94
|
+
0x05: "All On Entry Delay / Away Armed Entry Delay",
|
|
95
|
+
0x06: "Part On Entry Delay / Stay Armed Entry Delay",
|
|
96
|
+
0x07: "All On Exit Delay / Away Armed Exit Delay",
|
|
97
|
+
0x08: "Part On Exit Delay / Stay Armed Exit Delay",
|
|
98
|
+
0x09: "All On Instant Armed",
|
|
99
|
+
0x0A: "Stay 1 On",
|
|
100
|
+
0x0B: "Stay 2 On",
|
|
101
|
+
0x0C: "Away On",
|
|
102
|
+
0x0D: "Away Exit Delay",
|
|
103
|
+
0x0E: "Away Entry Delay",
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
AREA_READY_NOT = 0x00
|
|
107
|
+
AREA_READY_PART = 0x01
|
|
108
|
+
AREA_READY_ALL = 0x02
|
|
109
|
+
|
|
110
|
+
AREA_READY = {
|
|
111
|
+
0x00: "Not Ready",
|
|
112
|
+
0x01: "Part Ready",
|
|
113
|
+
0x02: "All Ready",
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
AREA_ARMING_DISARM = 0x01
|
|
117
|
+
AREA_ARMING_MASTER_DELAY = 0x03
|
|
118
|
+
AREA_ARMING_PERIMETER_DELAY = 0x05
|
|
119
|
+
AREA_ARMING_STAY1 = 0x0A
|
|
120
|
+
AREA_ARMING_STAY2 = 0x0B
|
|
121
|
+
AREA_ARMING_AWAY = 0x0C
|
|
122
|
+
|
|
123
|
+
POINT_STATUS_OPEN = 0x02
|
|
124
|
+
POINT_STATUS_NORMAL = 0x03
|
|
125
|
+
POINT_STATUS_UNKNOWN = 0xFF
|
|
126
|
+
|
|
127
|
+
POINT_STATUS = {
|
|
128
|
+
0x00: "Unassigned",
|
|
129
|
+
0x01: "Short",
|
|
130
|
+
0x02: "Open",
|
|
131
|
+
0x03: "Normal",
|
|
132
|
+
0x04: "Missing",
|
|
133
|
+
0x05: "Resistor 2",
|
|
134
|
+
0x06: "Resistor 3",
|
|
135
|
+
0xFF: "Unknown",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
ALARM_MEMORY_PRIORITY_ALARMS = [0x07, 0x09, 0x0A]
|
|
139
|
+
|
|
140
|
+
ALARM_MEMORY_PRIORITIES = {
|
|
141
|
+
0x01: "Burglary Trouble",
|
|
142
|
+
0x02: "Burglary Supervisory",
|
|
143
|
+
0x03: "Gas Trouble",
|
|
144
|
+
0x04: "Gas Supervisory",
|
|
145
|
+
0x05: "Fire Trouble",
|
|
146
|
+
0x06: "Fire Supervisory",
|
|
147
|
+
0x07: "Burglary Alarm",
|
|
148
|
+
0x08: "Personal Emergency",
|
|
149
|
+
0x09: "Gas Alarm",
|
|
150
|
+
0x0A: "Fire Alarm"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class CMD:
|
|
154
|
+
# Unauthenticated commands
|
|
155
|
+
WHAT_ARE_YOU = 0x01
|
|
156
|
+
AUTHENTICATE = 0x06
|
|
157
|
+
LOGIN_REMOTE_USER = 0x3E
|
|
158
|
+
# Alarm memory details
|
|
159
|
+
ALARM_MEMORY_SUMMARY = 0x08
|
|
160
|
+
ALARM_MEMORY_DETAIL = 0x23
|
|
161
|
+
# History details
|
|
162
|
+
REQUEST_RAW_HISTORY_EVENTS = 0x15
|
|
163
|
+
# Area group
|
|
164
|
+
REQUEST_CONFIGURED_AREAS = 0x24
|
|
165
|
+
AREA_STATUS = 0x26
|
|
166
|
+
AREA_ARM = 0x27
|
|
167
|
+
AREA_TEXT = 0x29
|
|
168
|
+
# Point group
|
|
169
|
+
REQUEST_CONFIGURED_POINTS = 0x35
|
|
170
|
+
POINT_STATUS = 0x38
|
|
171
|
+
POINT_TEXT = 0x3C
|
|
172
|
+
# System group
|
|
173
|
+
SET_SUBSCRIPTION = 0x5F
|
|
174
|
+
# Diagnostic group
|
|
175
|
+
PRODUCT_SERIAL = 0x4A
|
|
176
|
+
|