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.
@@ -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,3 @@
1
+ __version__ = '0.1.0'
2
+
3
+ from .panel import Panel
@@ -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
+