pyg90alarm 1.12.1__py3-none-any.whl → 1.14.0__py3-none-any.whl
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.
- pyg90alarm/__init__.py +31 -4
- pyg90alarm/alarm.py +193 -163
- pyg90alarm/base_cmd.py +60 -52
- pyg90alarm/callback.py +41 -51
- pyg90alarm/config.py +10 -6
- pyg90alarm/const.py +9 -2
- pyg90alarm/definitions/sensors.py +12 -11
- pyg90alarm/device_notifications.py +65 -41
- pyg90alarm/discovery.py +31 -22
- pyg90alarm/entities/device.py +6 -7
- pyg90alarm/entities/sensor.py +138 -120
- pyg90alarm/history.py +42 -41
- pyg90alarm/host_info.py +27 -25
- pyg90alarm/host_status.py +25 -12
- pyg90alarm/paginated_cmd.py +46 -33
- pyg90alarm/paginated_result.py +13 -7
- pyg90alarm/py.typed +0 -0
- pyg90alarm/targeted_discovery.py +98 -39
- pyg90alarm/user_data_crc.py +18 -13
- {pyg90alarm-1.12.1.dist-info → pyg90alarm-1.14.0.dist-info}/METADATA +4 -3
- pyg90alarm-1.14.0.dist-info/RECORD +27 -0
- {pyg90alarm-1.12.1.dist-info → pyg90alarm-1.14.0.dist-info}/WHEEL +1 -1
- pyg90alarm-1.12.1.dist-info/RECORD +0 -26
- {pyg90alarm-1.12.1.dist-info → pyg90alarm-1.14.0.dist-info}/LICENSE +0 -0
- {pyg90alarm-1.12.1.dist-info → pyg90alarm-1.14.0.dist-info}/top_level.txt +0 -0
pyg90alarm/entities/sensor.py
CHANGED
|
@@ -21,48 +21,67 @@
|
|
|
21
21
|
"""
|
|
22
22
|
Provides interface to sensors of G90 alarm panel.
|
|
23
23
|
"""
|
|
24
|
-
|
|
24
|
+
from __future__ import annotations
|
|
25
25
|
import logging
|
|
26
|
-
from
|
|
26
|
+
from dataclasses import dataclass, asdict, astuple
|
|
27
|
+
from typing import (
|
|
28
|
+
Any, Optional, TYPE_CHECKING, Dict
|
|
29
|
+
)
|
|
30
|
+
|
|
27
31
|
from enum import IntEnum, IntFlag
|
|
28
|
-
from ..definitions.sensors import SENSOR_DEFINITIONS
|
|
32
|
+
from ..definitions.sensors import SENSOR_DEFINITIONS, SensorDefinition
|
|
29
33
|
from ..const import G90Commands
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from ..alarm import G90Alarm, SensorStateCallback, SensorLowBatteryCallback
|
|
30
36
|
|
|
31
|
-
# Common protocol fields across read and write operations
|
|
32
|
-
COMMON_FIELDS = [
|
|
33
|
-
'parent_name',
|
|
34
|
-
'index',
|
|
35
|
-
'room_id',
|
|
36
|
-
'type_id',
|
|
37
|
-
'subtype',
|
|
38
|
-
'timeout',
|
|
39
|
-
'user_flag_data',
|
|
40
|
-
'baudrate',
|
|
41
|
-
'protocol_id',
|
|
42
|
-
'reserved_data',
|
|
43
|
-
'node_count',
|
|
44
|
-
]
|
|
45
|
-
|
|
46
|
-
# Incoming (read operation) protocol fields
|
|
47
|
-
INCOMING_FIELDS = COMMON_FIELDS + [
|
|
48
|
-
'mask',
|
|
49
|
-
'private_data',
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
# Outgoing (write operation) protocol fields
|
|
53
|
-
OUTGOING_FIELDS = COMMON_FIELDS + [
|
|
54
|
-
'rx',
|
|
55
|
-
'tx',
|
|
56
|
-
'private_data',
|
|
57
|
-
]
|
|
58
37
|
|
|
38
|
+
@dataclass
|
|
39
|
+
class G90SensorCommonData: # pylint:disable=too-many-instance-attributes
|
|
40
|
+
"""
|
|
41
|
+
Common protocol fields across read and write operations.
|
|
59
42
|
|
|
60
|
-
|
|
43
|
+
:meta private:
|
|
61
44
|
"""
|
|
62
|
-
|
|
45
|
+
parent_name: str
|
|
46
|
+
index: int
|
|
47
|
+
room_id: int
|
|
48
|
+
type_id: int
|
|
49
|
+
subtype: int
|
|
50
|
+
timeout: int
|
|
51
|
+
user_flag_data: int
|
|
52
|
+
baudrate: int
|
|
53
|
+
protocol_id: int
|
|
54
|
+
reserved_data: int
|
|
55
|
+
node_count: int
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class G90SensorIncomingData(G90SensorCommonData):
|
|
60
|
+
"""
|
|
61
|
+
Incoming (read operation) protocol fields.
|
|
63
62
|
|
|
64
63
|
:meta private:
|
|
65
64
|
"""
|
|
65
|
+
mask: int
|
|
66
|
+
private_data: str
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class G90SensorOutgoingData(G90SensorCommonData):
|
|
71
|
+
"""
|
|
72
|
+
Outgoing (write operation) protocol fields.
|
|
73
|
+
|
|
74
|
+
:meta private:
|
|
75
|
+
"""
|
|
76
|
+
rx: int # pylint:disable=invalid-name
|
|
77
|
+
tx: int # pylint:disable=invalid-name
|
|
78
|
+
private_data: str
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class G90SensorReservedFlags(IntFlag):
|
|
82
|
+
"""
|
|
83
|
+
Reserved flags of the sensor.
|
|
84
|
+
"""
|
|
66
85
|
NONE = 0
|
|
67
86
|
CAN_READ = 16
|
|
68
87
|
CAN_READ_EXT = 32
|
|
@@ -72,8 +91,6 @@ class G90SensorReservedFlags(IntFlag):
|
|
|
72
91
|
class G90SensorUserFlags(IntFlag):
|
|
73
92
|
"""
|
|
74
93
|
User flags of the sensor.
|
|
75
|
-
|
|
76
|
-
:meta private:
|
|
77
94
|
"""
|
|
78
95
|
NONE = 0
|
|
79
96
|
ENABLED = 1
|
|
@@ -89,8 +106,6 @@ class G90SensorUserFlags(IntFlag):
|
|
|
89
106
|
class G90SensorProtocols(IntEnum):
|
|
90
107
|
"""
|
|
91
108
|
Protocol types for the sensors.
|
|
92
|
-
|
|
93
|
-
:meta private:
|
|
94
109
|
"""
|
|
95
110
|
RF_1527 = 0
|
|
96
111
|
RF_2262 = 1
|
|
@@ -104,8 +119,6 @@ class G90SensorProtocols(IntEnum):
|
|
|
104
119
|
class G90SensorTypes(IntEnum):
|
|
105
120
|
"""
|
|
106
121
|
Sensor types.
|
|
107
|
-
|
|
108
|
-
:meta private:
|
|
109
122
|
"""
|
|
110
123
|
DOOR = 1
|
|
111
124
|
GLASS = 2
|
|
@@ -160,23 +173,22 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
160
173
|
:param kwargs: Pass-through keyword arguments for for interpreting protocol
|
|
161
174
|
fields
|
|
162
175
|
"""
|
|
163
|
-
def __init__(
|
|
164
|
-
self
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
self.
|
|
168
|
-
|
|
169
|
-
)
|
|
176
|
+
def __init__(
|
|
177
|
+
self, *args: Any, parent: G90Alarm, subindex: int, proto_idx: int,
|
|
178
|
+
**kwargs: Any
|
|
179
|
+
) -> None:
|
|
180
|
+
self._protocol_incoming_data_kls = G90SensorIncomingData
|
|
181
|
+
self._protocol_outgoing_data_kls = G90SensorOutgoingData
|
|
170
182
|
self._protocol_data = self._protocol_incoming_data_kls(*args, **kwargs)
|
|
171
183
|
self._parent = parent
|
|
172
184
|
self._subindex = subindex
|
|
173
185
|
self._occupancy = False
|
|
174
|
-
self._state_callback = None
|
|
175
|
-
self._low_battery_callback = None
|
|
186
|
+
self._state_callback: Optional[SensorStateCallback] = None
|
|
187
|
+
self._low_battery_callback: Optional[SensorLowBatteryCallback] = None
|
|
176
188
|
self._proto_idx = proto_idx
|
|
177
|
-
self._extra_data = None
|
|
189
|
+
self._extra_data: Any = None
|
|
178
190
|
|
|
179
|
-
self._definition = None
|
|
191
|
+
self._definition: Optional[SensorDefinition] = None
|
|
180
192
|
# Get sensor definition corresponds to the sensor type/subtype if any
|
|
181
193
|
for s_def in SENSOR_DEFINITIONS:
|
|
182
194
|
if (
|
|
@@ -187,184 +199,168 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
187
199
|
break
|
|
188
200
|
|
|
189
201
|
@property
|
|
190
|
-
def name(self):
|
|
202
|
+
def name(self) -> str:
|
|
191
203
|
"""
|
|
192
|
-
|
|
204
|
+
Sensor name, accounting for multi-channel entities (single
|
|
193
205
|
protocol entity results in multiple :class:`.G90Sensor` instances).
|
|
194
206
|
|
|
195
207
|
:return: Sensor name
|
|
196
|
-
:rtype: str
|
|
197
208
|
"""
|
|
198
209
|
if self._protocol_data.node_count == 1:
|
|
199
210
|
return self._protocol_data.parent_name
|
|
200
211
|
return f'{self._protocol_data.parent_name}#{self._subindex + 1}'
|
|
201
212
|
|
|
202
213
|
@property
|
|
203
|
-
def state_callback(self):
|
|
214
|
+
def state_callback(self) -> Optional[SensorStateCallback]:
|
|
204
215
|
"""
|
|
205
|
-
|
|
216
|
+
Callback that is invoked when the sensor changes its state.
|
|
206
217
|
|
|
207
218
|
:return: Sensor state callback
|
|
208
|
-
:rtype: object
|
|
209
219
|
"""
|
|
210
220
|
return self._state_callback
|
|
211
221
|
|
|
212
222
|
@state_callback.setter
|
|
213
|
-
def state_callback(self, value):
|
|
214
|
-
"""
|
|
215
|
-
Sets callback for the state changes of the sensor.
|
|
216
|
-
|
|
217
|
-
:param object value: Sensor state callback
|
|
218
|
-
"""
|
|
223
|
+
def state_callback(self, value: SensorStateCallback) -> None:
|
|
219
224
|
self._state_callback = value
|
|
220
225
|
|
|
221
226
|
@property
|
|
222
|
-
def low_battery_callback(self):
|
|
227
|
+
def low_battery_callback(self) -> Optional[SensorLowBatteryCallback]:
|
|
223
228
|
"""
|
|
224
|
-
|
|
229
|
+
Callback that is invoked when the sensor reports on low battery
|
|
230
|
+
condition.
|
|
225
231
|
|
|
226
232
|
:return: Sensor's low battery callback
|
|
227
|
-
:rtype: object
|
|
228
233
|
"""
|
|
229
234
|
return self._low_battery_callback
|
|
230
235
|
|
|
231
236
|
@low_battery_callback.setter
|
|
232
|
-
def low_battery_callback(self, value):
|
|
233
|
-
"""
|
|
234
|
-
Sets callback for the low battery condition reported by the sensor.
|
|
235
|
-
|
|
236
|
-
:param object value: Sensor's low battery callback
|
|
237
|
-
"""
|
|
237
|
+
def low_battery_callback(self, value: SensorLowBatteryCallback) -> None:
|
|
238
238
|
self._low_battery_callback = value
|
|
239
239
|
|
|
240
240
|
@property
|
|
241
|
-
def occupancy(self):
|
|
241
|
+
def occupancy(self) -> bool:
|
|
242
242
|
"""
|
|
243
243
|
Occupancy (occupied/not occupied, or triggered/not triggered)
|
|
244
244
|
for the sensor.
|
|
245
245
|
|
|
246
246
|
:return: Sensor occupancy
|
|
247
|
-
:rtype: bool
|
|
248
247
|
"""
|
|
249
248
|
return self._occupancy
|
|
250
249
|
|
|
251
250
|
@occupancy.setter
|
|
252
|
-
def occupancy(self, value):
|
|
253
|
-
"""
|
|
254
|
-
Sets occupancy state for the sensor.
|
|
255
|
-
|
|
256
|
-
:param bool value: Sensor occupancy
|
|
257
|
-
"""
|
|
251
|
+
def occupancy(self, value: bool) -> None:
|
|
258
252
|
self._occupancy = value
|
|
259
253
|
|
|
260
254
|
@property
|
|
261
|
-
def protocol(self):
|
|
255
|
+
def protocol(self) -> G90SensorProtocols:
|
|
262
256
|
"""
|
|
263
|
-
|
|
257
|
+
Protocol type of the sensor.
|
|
264
258
|
|
|
265
259
|
:return: Protocol type
|
|
266
|
-
:rtype: int
|
|
267
260
|
"""
|
|
268
261
|
return G90SensorProtocols(self._protocol_data.protocol_id)
|
|
269
262
|
|
|
270
263
|
@property
|
|
271
|
-
def type(self):
|
|
264
|
+
def type(self) -> G90SensorTypes:
|
|
272
265
|
"""
|
|
273
|
-
|
|
266
|
+
Type of the sensor.
|
|
274
267
|
|
|
275
268
|
:return: Sensor type
|
|
276
|
-
:rtype: int
|
|
277
269
|
"""
|
|
278
270
|
return G90SensorTypes(self._protocol_data.type_id)
|
|
279
271
|
|
|
280
272
|
@property
|
|
281
|
-
def
|
|
273
|
+
def subtype(self) -> int:
|
|
274
|
+
"""
|
|
275
|
+
Sub-type of the sensor.
|
|
276
|
+
|
|
277
|
+
:return: Sensor sub-type
|
|
282
278
|
"""
|
|
283
|
-
|
|
279
|
+
return self._protocol_data.subtype
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def reserved(self) -> G90SensorReservedFlags:
|
|
283
|
+
"""
|
|
284
|
+
Reserved flags (read/write mode) for the sensor.
|
|
284
285
|
|
|
285
286
|
:return: Reserved flags
|
|
286
|
-
:rtype: int
|
|
287
287
|
"""
|
|
288
288
|
return G90SensorReservedFlags(self._protocol_data.reserved_data)
|
|
289
289
|
|
|
290
290
|
@property
|
|
291
|
-
def user_flag(self):
|
|
291
|
+
def user_flag(self) -> G90SensorUserFlags:
|
|
292
292
|
"""
|
|
293
|
-
|
|
293
|
+
User flags for the sensor (disabled/enabled, arming type etc).
|
|
294
294
|
|
|
295
295
|
:return: User flags
|
|
296
|
-
:rtype: int
|
|
297
296
|
"""
|
|
298
297
|
return G90SensorUserFlags(self._protocol_data.user_flag_data)
|
|
299
298
|
|
|
300
299
|
@property
|
|
301
|
-
def node_count(self):
|
|
300
|
+
def node_count(self) -> int:
|
|
302
301
|
"""
|
|
303
|
-
|
|
302
|
+
Number of nodes (channels) for the sensor.
|
|
304
303
|
|
|
305
304
|
:return: Number of nodes
|
|
306
|
-
:rtype: int
|
|
307
305
|
"""
|
|
308
306
|
return self._protocol_data.node_count
|
|
309
307
|
|
|
310
308
|
@property
|
|
311
|
-
def parent(self):
|
|
309
|
+
def parent(self) -> G90Alarm:
|
|
312
310
|
"""
|
|
313
|
-
|
|
311
|
+
Parent instance of alarm panel class the sensor is associated
|
|
314
312
|
with.
|
|
315
313
|
|
|
316
|
-
:return: Parent
|
|
317
|
-
:rtype: :class:`.G90Alarm`
|
|
314
|
+
:return: Parent instance
|
|
318
315
|
"""
|
|
319
316
|
return self._parent
|
|
320
317
|
|
|
321
318
|
@property
|
|
322
|
-
def index(self):
|
|
319
|
+
def index(self) -> int:
|
|
323
320
|
"""
|
|
324
|
-
|
|
321
|
+
Index (internal position) of the sensor in the alarm panel.
|
|
325
322
|
|
|
326
323
|
:return: Internal sensor position
|
|
327
|
-
:rtype: int
|
|
328
324
|
"""
|
|
329
325
|
return self._protocol_data.index
|
|
330
326
|
|
|
331
327
|
@property
|
|
332
|
-
def subindex(self):
|
|
328
|
+
def subindex(self) -> int:
|
|
333
329
|
"""
|
|
334
|
-
|
|
330
|
+
Index of the sensor within multi-node device.
|
|
335
331
|
|
|
336
332
|
:return: Index of sensor in multi-node device.
|
|
337
|
-
:rtype: int
|
|
338
333
|
"""
|
|
339
334
|
return self._subindex
|
|
340
335
|
|
|
341
336
|
@property
|
|
342
|
-
def supports_enable_disable(self):
|
|
337
|
+
def supports_enable_disable(self) -> bool:
|
|
343
338
|
"""
|
|
344
339
|
Indicates if disabling/enabling the sensor is supported.
|
|
345
340
|
|
|
346
341
|
:return: Support for enabling/disabling the sensor
|
|
347
|
-
:rtype: bool
|
|
348
342
|
"""
|
|
349
343
|
return self._definition is not None
|
|
350
344
|
|
|
351
345
|
@property
|
|
352
|
-
def enabled(self):
|
|
346
|
+
def enabled(self) -> bool:
|
|
353
347
|
"""
|
|
354
348
|
Indicates if the sensor is enabled.
|
|
355
349
|
|
|
356
350
|
:return: If sensor is enabled
|
|
357
|
-
:rtype: bool
|
|
358
351
|
"""
|
|
359
|
-
return self.user_flag & G90SensorUserFlags.ENABLED
|
|
352
|
+
return self.user_flag & G90SensorUserFlags.ENABLED != 0
|
|
360
353
|
|
|
361
|
-
async def set_enabled(self, value):
|
|
354
|
+
async def set_enabled(self, value: bool) -> None:
|
|
362
355
|
"""
|
|
363
356
|
Sets disabled/enabled state of the sensor.
|
|
364
357
|
|
|
365
|
-
:param
|
|
358
|
+
:param value: Whether to enable or disable the sensor
|
|
366
359
|
"""
|
|
367
|
-
|
|
360
|
+
# Checking private attribute directly, since `mypy` doesn't recognize
|
|
361
|
+
# the check for sensor definition to be defined if done over
|
|
362
|
+
# `self.supports_enable_disable` property
|
|
363
|
+
if not self._definition:
|
|
368
364
|
_LOGGER.warning(
|
|
369
365
|
'Manipulating with enable/disable for sensor index=%s'
|
|
370
366
|
' is unsupported - no sensor definition for'
|
|
@@ -388,7 +384,7 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
388
384
|
G90Commands.GETSENSORLIST,
|
|
389
385
|
start=self._proto_idx, end=self._proto_idx
|
|
390
386
|
)
|
|
391
|
-
sensors = [x async for x in sensors_result]
|
|
387
|
+
sensors = [x.data async for x in sensors_result]
|
|
392
388
|
|
|
393
389
|
# Abort if sensor is not found
|
|
394
390
|
if not sensors:
|
|
@@ -401,7 +397,7 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
401
397
|
|
|
402
398
|
# Compare actual sensor data from what the sensor has been instantiated
|
|
403
399
|
# from, and abort the operation if out-of-band changes are detected.
|
|
404
|
-
|
|
400
|
+
sensor_data = sensors[0]
|
|
405
401
|
if self._protocol_incoming_data_kls(
|
|
406
402
|
*sensor_data
|
|
407
403
|
) != self._protocol_data:
|
|
@@ -422,7 +418,7 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
422
418
|
user_flag &= ~G90SensorUserFlags.ENABLED
|
|
423
419
|
|
|
424
420
|
# Re-instantiate the protocol data with modified user flags
|
|
425
|
-
_data = self._protocol_data
|
|
421
|
+
_data = asdict(self._protocol_data)
|
|
426
422
|
_data['user_flag_data'] = user_flag
|
|
427
423
|
self._protocol_data = self._protocol_incoming_data_kls(**_data)
|
|
428
424
|
|
|
@@ -454,30 +450,52 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
|
|
|
454
450
|
)
|
|
455
451
|
# Modify the sensor
|
|
456
452
|
await self._parent.command(
|
|
457
|
-
G90Commands.SETSINGLESENSOR, list(outgoing_data)
|
|
453
|
+
G90Commands.SETSINGLESENSOR, list(astuple(outgoing_data))
|
|
458
454
|
)
|
|
459
455
|
|
|
460
456
|
@property
|
|
461
|
-
def extra_data(self):
|
|
457
|
+
def extra_data(self) -> Any:
|
|
462
458
|
"""
|
|
463
|
-
|
|
459
|
+
Extra data for the sensor, that can be used to store
|
|
464
460
|
caller-specific information and will be carried by the sensor instance.
|
|
465
461
|
"""
|
|
466
462
|
return self._extra_data
|
|
467
463
|
|
|
468
464
|
@extra_data.setter
|
|
469
|
-
def extra_data(self, val):
|
|
465
|
+
def extra_data(self, val: Any) -> None:
|
|
470
466
|
self._extra_data = val
|
|
471
467
|
|
|
472
|
-
def
|
|
468
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
469
|
+
"""
|
|
470
|
+
Returns dictionary representation of the sensor.
|
|
471
|
+
|
|
472
|
+
:return: Dictionary representation
|
|
473
|
+
"""
|
|
474
|
+
return {
|
|
475
|
+
'name': self.name,
|
|
476
|
+
'type': self.type,
|
|
477
|
+
'subtype': self.subtype,
|
|
478
|
+
'index': self.index,
|
|
479
|
+
'subindex': self.subindex,
|
|
480
|
+
'node_count': self.node_count,
|
|
481
|
+
'protocol': self.protocol,
|
|
482
|
+
'occupancy': self.occupancy,
|
|
483
|
+
'user_flag': self.user_flag,
|
|
484
|
+
'reserved': self.reserved,
|
|
485
|
+
'extra_data': self.extra_data,
|
|
486
|
+
'enabled': self.enabled,
|
|
487
|
+
'supports_enable_disable': self.supports_enable_disable,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
def __repr__(self) -> str:
|
|
473
491
|
"""
|
|
474
492
|
Returns string representation of the sensor.
|
|
475
493
|
|
|
476
494
|
:return: String representation
|
|
477
|
-
:rtype: str
|
|
478
495
|
"""
|
|
479
496
|
return super().__repr__() + f"(name='{str(self.name)}'" \
|
|
480
497
|
f' type={str(self.type)}' \
|
|
498
|
+
f' subtype={str(self.subtype)}' \
|
|
481
499
|
f' protocol={str(self.protocol)}' \
|
|
482
500
|
f' occupancy={self.occupancy}' \
|
|
483
501
|
f' user flag={str(self.user_flag)}' \
|
pyg90alarm/history.py
CHANGED
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"""
|
|
22
22
|
History protocol entity.
|
|
23
23
|
"""
|
|
24
|
-
|
|
24
|
+
from typing import Any, Optional, Dict
|
|
25
|
+
from dataclasses import dataclass
|
|
25
26
|
from datetime import datetime, timezone
|
|
26
|
-
from collections import namedtuple
|
|
27
27
|
from .const import (
|
|
28
28
|
G90AlertTypes,
|
|
29
29
|
G90AlertSources,
|
|
@@ -65,52 +65,50 @@ states_mapping = {
|
|
|
65
65
|
G90HistoryStates.WIFI_DISCONNECTED,
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class ProtocolData:
|
|
71
|
+
"""
|
|
72
|
+
Class representing the data incoming from the device
|
|
73
|
+
|
|
74
|
+
:meta private:
|
|
75
|
+
"""
|
|
76
|
+
type: G90AlertTypes
|
|
77
|
+
event_id: G90AlertStateChangeTypes
|
|
78
|
+
source: G90AlertSources
|
|
79
|
+
state: int
|
|
80
|
+
sensor_name: str
|
|
81
|
+
unix_time: int
|
|
82
|
+
other: str
|
|
79
83
|
|
|
80
84
|
|
|
81
85
|
class G90History:
|
|
82
86
|
"""
|
|
83
|
-
|
|
87
|
+
Represents a history entry from the alarm panel.
|
|
84
88
|
"""
|
|
85
|
-
def __init__(self, *args, **kwargs):
|
|
89
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
|
86
90
|
self._protocol_data = ProtocolData(*args, **kwargs)
|
|
87
91
|
|
|
88
92
|
@property
|
|
89
|
-
def datetime(self):
|
|
93
|
+
def datetime(self) -> datetime:
|
|
90
94
|
"""
|
|
91
95
|
Date/time of the history entry.
|
|
92
|
-
|
|
93
|
-
:rtype: :class:`datetime.datetime`
|
|
94
96
|
"""
|
|
95
97
|
return datetime.fromtimestamp(
|
|
96
98
|
self._protocol_data.unix_time, tz=timezone.utc
|
|
97
99
|
)
|
|
98
100
|
|
|
99
101
|
@property
|
|
100
|
-
def type(self):
|
|
102
|
+
def type(self) -> G90AlertTypes:
|
|
101
103
|
"""
|
|
102
104
|
Type of the history entry.
|
|
103
|
-
|
|
104
|
-
:rtype: :class:`.G90AlertTypes`
|
|
105
105
|
"""
|
|
106
106
|
return G90AlertTypes(self._protocol_data.type)
|
|
107
107
|
|
|
108
108
|
@property
|
|
109
|
-
def state(self):
|
|
109
|
+
def state(self) -> G90HistoryStates:
|
|
110
110
|
"""
|
|
111
111
|
State for the history entry.
|
|
112
|
-
|
|
113
|
-
:rtype: :class:`.G90HistoryStates`
|
|
114
112
|
"""
|
|
115
113
|
# Door open/close type, mapped against `G90AlertStates` using `state`
|
|
116
114
|
# incoming field
|
|
@@ -140,11 +138,9 @@ class G90History:
|
|
|
140
138
|
)
|
|
141
139
|
|
|
142
140
|
@property
|
|
143
|
-
def source(self):
|
|
141
|
+
def source(self) -> G90AlertSources:
|
|
144
142
|
"""
|
|
145
143
|
Source of the history entry.
|
|
146
|
-
|
|
147
|
-
:rtype: :class:`.G90AlertSources`
|
|
148
144
|
"""
|
|
149
145
|
# Device state changes or open/close events are mapped against
|
|
150
146
|
# `G90AlertSources` using `source` incoming field
|
|
@@ -162,22 +158,18 @@ class G90History:
|
|
|
162
158
|
return G90AlertSources.DEVICE
|
|
163
159
|
|
|
164
160
|
@property
|
|
165
|
-
def sensor_name(self):
|
|
161
|
+
def sensor_name(self) -> Optional[str]:
|
|
166
162
|
"""
|
|
167
163
|
Name of the sensor related to the history entry, might be empty if none
|
|
168
164
|
associated.
|
|
169
|
-
|
|
170
|
-
:rtype: str|None
|
|
171
165
|
"""
|
|
172
166
|
return self._protocol_data.sensor_name or None
|
|
173
167
|
|
|
174
168
|
@property
|
|
175
|
-
def sensor_idx(self):
|
|
169
|
+
def sensor_idx(self) -> Optional[int]:
|
|
176
170
|
"""
|
|
177
171
|
ID of the sensor related to the history entry, might be empty if none
|
|
178
172
|
associated.
|
|
179
|
-
|
|
180
|
-
:rtype: str|None
|
|
181
173
|
"""
|
|
182
174
|
# Sensor ID will only be available if entry source is a sensor
|
|
183
175
|
if self.source == G90AlertSources.SENSOR:
|
|
@@ -185,12 +177,10 @@ class G90History:
|
|
|
185
177
|
|
|
186
178
|
return None
|
|
187
179
|
|
|
188
|
-
def as_device_alert(self):
|
|
180
|
+
def as_device_alert(self) -> G90DeviceAlert:
|
|
189
181
|
"""
|
|
190
182
|
Returns the history entry represented as device alert structure,
|
|
191
183
|
suitable for :meth:`G90DeviceNotifications._handle_alert`.
|
|
192
|
-
|
|
193
|
-
:rtype: :class:`.G90DeviceAlert`
|
|
194
184
|
"""
|
|
195
185
|
return G90DeviceAlert(
|
|
196
186
|
type=self._protocol_data.type,
|
|
@@ -198,17 +188,28 @@ class G90History:
|
|
|
198
188
|
source=self._protocol_data.source,
|
|
199
189
|
state=self._protocol_data.state,
|
|
200
190
|
zone_name=self._protocol_data.sensor_name,
|
|
201
|
-
device_id=
|
|
191
|
+
device_id='',
|
|
202
192
|
unix_time=self._protocol_data.unix_time,
|
|
203
|
-
resv4=
|
|
193
|
+
resv4=0,
|
|
204
194
|
other=self._protocol_data.other
|
|
205
195
|
)
|
|
206
196
|
|
|
207
|
-
def
|
|
197
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
208
198
|
"""
|
|
209
|
-
|
|
199
|
+
Returns the history entry as dictionary.
|
|
200
|
+
"""
|
|
201
|
+
return {
|
|
202
|
+
'type': self.type,
|
|
203
|
+
'source': self.source,
|
|
204
|
+
'state': self.state,
|
|
205
|
+
'sensor_name': self.sensor_name,
|
|
206
|
+
'sensor_idx': self.sensor_idx,
|
|
207
|
+
'datetime': self.datetime,
|
|
208
|
+
}
|
|
210
209
|
|
|
211
|
-
|
|
210
|
+
def __repr__(self) -> str:
|
|
211
|
+
"""
|
|
212
|
+
Textural representation of the history entry.
|
|
212
213
|
"""
|
|
213
214
|
return f'type={repr(self.type)}' \
|
|
214
215
|
+ f' source={repr(self.source)}' \
|