pyg90alarm 2.1.1__py3-none-any.whl → 2.2.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 +28 -6
- pyg90alarm/alarm.py +248 -54
- pyg90alarm/callback.py +41 -3
- pyg90alarm/cloud/messages.py +7 -7
- pyg90alarm/const.py +4 -1
- pyg90alarm/definitions/base.py +247 -0
- pyg90alarm/definitions/devices.py +366 -0
- pyg90alarm/definitions/sensors.py +812 -828
- pyg90alarm/entities/base_entity.py +10 -0
- pyg90alarm/entities/base_list.py +136 -33
- pyg90alarm/entities/device.py +23 -1
- pyg90alarm/entities/device_list.py +99 -1
- pyg90alarm/entities/sensor.py +83 -89
- pyg90alarm/entities/sensor_list.py +136 -3
- pyg90alarm/exceptions.py +24 -0
- pyg90alarm/local/base_cmd.py +34 -12
- pyg90alarm/local/notifications.py +3 -3
- pyg90alarm/notifications/base.py +29 -2
- pyg90alarm/notifications/protocol.py +11 -0
- {pyg90alarm-2.1.1.dist-info → pyg90alarm-2.2.0.dist-info}/METADATA +1 -1
- pyg90alarm-2.2.0.dist-info/RECORD +42 -0
- {pyg90alarm-2.1.1.dist-info → pyg90alarm-2.2.0.dist-info}/WHEEL +1 -1
- pyg90alarm-2.1.1.dist-info/RECORD +0 -40
- {pyg90alarm-2.1.1.dist-info → pyg90alarm-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {pyg90alarm-2.1.1.dist-info → pyg90alarm-2.2.0.dist-info}/top_level.txt +0 -0
pyg90alarm/__init__.py
CHANGED
|
@@ -29,12 +29,21 @@ from .notifications.base import (
|
|
|
29
29
|
G90DeviceAlert,
|
|
30
30
|
)
|
|
31
31
|
from .entities.sensor import (
|
|
32
|
-
G90Sensor,
|
|
32
|
+
G90Sensor, G90SensorAlertModes, G90SensorUserFlags
|
|
33
33
|
)
|
|
34
34
|
from .entities.device import G90Device
|
|
35
35
|
from .local.host_info import (
|
|
36
36
|
G90HostInfo, G90HostInfoWifiStatus, G90HostInfoGsmStatus
|
|
37
37
|
)
|
|
38
|
+
from .definitions.sensors import (
|
|
39
|
+
G90SensorDefinitions
|
|
40
|
+
)
|
|
41
|
+
from .definitions.devices import (
|
|
42
|
+
G90DeviceDefinitions
|
|
43
|
+
)
|
|
44
|
+
from .definitions.base import (
|
|
45
|
+
G90PeripheralTypes,
|
|
46
|
+
)
|
|
38
47
|
from .local.config import G90AlertConfigFlags
|
|
39
48
|
from .local.host_status import G90HostStatus
|
|
40
49
|
from .const import (
|
|
@@ -47,16 +56,29 @@ from .const import (
|
|
|
47
56
|
G90AlertStateChangeTypes,
|
|
48
57
|
G90HistoryStates,
|
|
49
58
|
)
|
|
50
|
-
from .exceptions import
|
|
59
|
+
from .exceptions import (
|
|
60
|
+
G90Error, G90TimeoutError, G90CommandError, G90CommandFailure,
|
|
61
|
+
G90EntityRegistrationError, G90PeripheralDefinitionNotFound,
|
|
62
|
+
)
|
|
51
63
|
|
|
52
64
|
__all__ = [
|
|
53
65
|
'G90Alarm', 'G90BaseCommand', 'G90PaginatedResult', 'G90DeviceAlert',
|
|
54
|
-
|
|
55
|
-
'
|
|
66
|
+
# Sensors and related
|
|
67
|
+
'G90Sensor', 'G90PeripheralTypes', 'G90SensorAlertModes',
|
|
68
|
+
'G90SensorUserFlags',
|
|
69
|
+
'G90AlertConfigFlags',
|
|
70
|
+
'G90Device',
|
|
71
|
+
# Panel information and status
|
|
56
72
|
'G90HostInfo', 'G90HostInfoWifiStatus', 'G90HostInfoGsmStatus',
|
|
57
73
|
'G90HostStatus',
|
|
74
|
+
# Types for alerts and notifications
|
|
58
75
|
'G90MessageTypes', 'G90NotificationTypes', 'G90ArmDisarmTypes',
|
|
59
76
|
'G90AlertTypes', 'G90AlertSources', 'G90AlertStates',
|
|
60
|
-
'G90AlertStateChangeTypes', 'G90HistoryStates',
|
|
61
|
-
|
|
77
|
+
'G90AlertStateChangeTypes', 'G90HistoryStates',
|
|
78
|
+
# Exceptions
|
|
79
|
+
'G90Error',
|
|
80
|
+
'G90TimeoutError', 'G90CommandError', 'G90CommandFailure',
|
|
81
|
+
'G90EntityRegistrationError', 'G90PeripheralDefinitionNotFound',
|
|
82
|
+
# Definitions
|
|
83
|
+
'G90SensorDefinitions', 'G90DeviceDefinitions'
|
|
62
84
|
]
|
pyg90alarm/alarm.py
CHANGED
|
@@ -69,15 +69,21 @@ from .const import (
|
|
|
69
69
|
CLOUD_NOTIFICATIONS_PORT,
|
|
70
70
|
REMOTE_CLOUD_HOST,
|
|
71
71
|
REMOTE_CLOUD_PORT,
|
|
72
|
+
DEVICE_REGISTRATION_TIMEOUT,
|
|
73
|
+
ROOM_ID,
|
|
72
74
|
G90ArmDisarmTypes,
|
|
73
75
|
G90RemoteButtonStates,
|
|
74
76
|
)
|
|
75
77
|
from .local.base_cmd import (G90BaseCommand, G90BaseCommandData)
|
|
76
78
|
from .local.paginated_result import G90PaginatedResult, G90PaginatedResponse
|
|
77
|
-
from .entities.
|
|
79
|
+
from .entities.base_list import ListChangeCallback
|
|
80
|
+
from .entities.sensor import G90Sensor
|
|
78
81
|
from .entities.sensor_list import G90SensorList
|
|
79
82
|
from .entities.device import G90Device
|
|
80
83
|
from .entities.device_list import G90DeviceList
|
|
84
|
+
from .definitions.base import (
|
|
85
|
+
G90PeripheralTypes
|
|
86
|
+
)
|
|
81
87
|
from .notifications.protocol import (
|
|
82
88
|
G90NotificationProtocol
|
|
83
89
|
)
|
|
@@ -92,7 +98,7 @@ from .local.host_status import G90HostStatus
|
|
|
92
98
|
from .local.config import (G90AlertConfig, G90AlertConfigFlags)
|
|
93
99
|
from .local.history import G90History
|
|
94
100
|
from .local.user_data_crc import G90UserDataCRC
|
|
95
|
-
from .callback import G90Callback
|
|
101
|
+
from .callback import G90Callback, G90CallbackList
|
|
96
102
|
from .exceptions import G90Error, G90TimeoutError
|
|
97
103
|
from .cloud.notifications import G90CloudNotifications
|
|
98
104
|
|
|
@@ -159,6 +165,10 @@ if TYPE_CHECKING:
|
|
|
159
165
|
Callable[[], None],
|
|
160
166
|
Callable[[], Coroutine[None, None, None]]
|
|
161
167
|
]
|
|
168
|
+
SensorChangeCallback = Union[
|
|
169
|
+
Callable[[int, str, bool], None],
|
|
170
|
+
Callable[[int, str, bool], Coroutine[None, None, None]]
|
|
171
|
+
]
|
|
162
172
|
|
|
163
173
|
|
|
164
174
|
# pylint: disable=too-many-public-methods
|
|
@@ -186,20 +196,37 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
186
196
|
self._port: int = port
|
|
187
197
|
self._notifications: Optional[G90NotificationsBase] = None
|
|
188
198
|
self._sensors = G90SensorList(self)
|
|
199
|
+
# The callback will be invoked when sensor list changes, e.g. sensor is
|
|
200
|
+
# added or updated
|
|
201
|
+
self._sensors.list_change_callback = self.on_sensor_list_change
|
|
189
202
|
self._devices = G90DeviceList(self)
|
|
190
|
-
|
|
191
|
-
self.
|
|
192
|
-
self.
|
|
193
|
-
self.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
self.
|
|
203
|
+
# Similarly for the device list
|
|
204
|
+
self._devices.list_change_callback = self.on_device_list_change
|
|
205
|
+
self._sensor_cb: G90CallbackList[SensorCallback] = G90CallbackList()
|
|
206
|
+
self._armdisarm_cb: G90CallbackList[ArmDisarmCallback] = (
|
|
207
|
+
G90CallbackList()
|
|
208
|
+
)
|
|
209
|
+
self._door_open_close_cb: G90CallbackList[DoorOpenCloseCallback] = (
|
|
210
|
+
G90CallbackList()
|
|
211
|
+
)
|
|
212
|
+
self._alarm_cb: G90CallbackList[AlarmCallback] = G90CallbackList()
|
|
213
|
+
self._low_battery_cb: G90CallbackList[LowBatteryCallback] = (
|
|
214
|
+
G90CallbackList()
|
|
215
|
+
)
|
|
216
|
+
self._sos_cb: G90CallbackList[SosCallback] = G90CallbackList()
|
|
217
|
+
self._remote_button_press_cb: G90CallbackList[
|
|
197
218
|
RemoteButtonPressCallback
|
|
198
|
-
] =
|
|
199
|
-
self._door_open_when_arming_cb:
|
|
219
|
+
] = G90CallbackList()
|
|
220
|
+
self._door_open_when_arming_cb: G90CallbackList[
|
|
200
221
|
DoorOpenWhenArmingCallback
|
|
201
|
-
] =
|
|
202
|
-
self._tamper_cb:
|
|
222
|
+
] = G90CallbackList()
|
|
223
|
+
self._tamper_cb: G90CallbackList[TamperCallback] = G90CallbackList()
|
|
224
|
+
self._sensor_list_change_cb: G90CallbackList[
|
|
225
|
+
ListChangeCallback[G90Sensor]
|
|
226
|
+
] = G90CallbackList()
|
|
227
|
+
self._device_list_change_cb: G90CallbackList[
|
|
228
|
+
ListChangeCallback[G90Device]
|
|
229
|
+
] = G90CallbackList()
|
|
203
230
|
self._reset_occupancy_interval = reset_occupancy_interval
|
|
204
231
|
self._alert_config = G90AlertConfig(self)
|
|
205
232
|
self._sms_alert_when_armed = False
|
|
@@ -322,6 +349,23 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
322
349
|
"""
|
|
323
350
|
return await self._sensors.find(idx, name, exclude_unavailable)
|
|
324
351
|
|
|
352
|
+
async def register_sensor(
|
|
353
|
+
self, definition_name: str, name: Optional[str] = None,
|
|
354
|
+
timeout: float = DEVICE_REGISTRATION_TIMEOUT
|
|
355
|
+
) -> G90Sensor:
|
|
356
|
+
"""
|
|
357
|
+
Registers the sensor with the panel.
|
|
358
|
+
|
|
359
|
+
:param definition_name: Name of the sensor definition to register
|
|
360
|
+
:param name: Optional name of the sensor to register, if not provided
|
|
361
|
+
the name will be taken from the definition
|
|
362
|
+
:param timeout: Timeout for the registration process, in seconds
|
|
363
|
+
:return: Sensor instance
|
|
364
|
+
"""
|
|
365
|
+
return await self._sensors.register(
|
|
366
|
+
definition_name, ROOM_ID, timeout, name
|
|
367
|
+
)
|
|
368
|
+
|
|
325
369
|
@property
|
|
326
370
|
async def devices(self) -> List[G90Device]:
|
|
327
371
|
"""
|
|
@@ -344,6 +388,37 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
344
388
|
"""
|
|
345
389
|
return await self._devices.update()
|
|
346
390
|
|
|
391
|
+
async def find_device(
|
|
392
|
+
self, idx: int, name: str, exclude_unavailable: bool = True
|
|
393
|
+
) -> Optional[G90Device]:
|
|
394
|
+
"""
|
|
395
|
+
Finds device by index and name.
|
|
396
|
+
|
|
397
|
+
:param idx: Device index
|
|
398
|
+
:param name: Device name
|
|
399
|
+
:param exclude_unavailable: Flag indicating if unavailable devices
|
|
400
|
+
should be excluded from the search
|
|
401
|
+
:return: Device instance
|
|
402
|
+
"""
|
|
403
|
+
return await self._devices.find(idx, name, exclude_unavailable)
|
|
404
|
+
|
|
405
|
+
async def register_device(
|
|
406
|
+
self, definition_name: str, name: Optional[str] = None,
|
|
407
|
+
timeout: float = DEVICE_REGISTRATION_TIMEOUT
|
|
408
|
+
) -> G90Device:
|
|
409
|
+
"""
|
|
410
|
+
Registers device (relay, switch) with the panel.
|
|
411
|
+
|
|
412
|
+
:param definition_name: Name of the device definition to register
|
|
413
|
+
:param name: Optional name of the device to register, if not provided
|
|
414
|
+
the name will be taken from the definition
|
|
415
|
+
:param timeout: Timeout for the registration process, in seconds
|
|
416
|
+
:return: Device instance
|
|
417
|
+
"""
|
|
418
|
+
return await self._devices.register(
|
|
419
|
+
definition_name, ROOM_ID, timeout, name
|
|
420
|
+
)
|
|
421
|
+
|
|
347
422
|
@property
|
|
348
423
|
async def host_info(self) -> G90HostInfo:
|
|
349
424
|
"""
|
|
@@ -396,7 +471,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
396
471
|
async def get_alert_config(self) -> G90AlertConfigFlags:
|
|
397
472
|
"""
|
|
398
473
|
Provides alert configuration flags, retained for compatibility - using
|
|
399
|
-
|
|
474
|
+
:attr:`alert_config` and :class:`.G90AlertConfig` is preferred.
|
|
400
475
|
|
|
401
476
|
:return: The alerts configured
|
|
402
477
|
"""
|
|
@@ -405,7 +480,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
405
480
|
async def set_alert_config(self, flags: G90AlertConfigFlags) -> None:
|
|
406
481
|
"""
|
|
407
482
|
Sets the alert configuration flags, retained for compatibility - using
|
|
408
|
-
|
|
483
|
+
:attr:`alert_config` and :class:`.G90AlertConfig` is preferred.
|
|
409
484
|
"""
|
|
410
485
|
await self.alert_config.set(flags)
|
|
411
486
|
|
|
@@ -489,7 +564,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
489
564
|
# notification itself
|
|
490
565
|
def reset_sensor_occupancy(sensor: G90Sensor) -> None:
|
|
491
566
|
sensor._set_occupancy(False)
|
|
492
|
-
|
|
567
|
+
sensor.state_callback.invoke(sensor.occupancy)
|
|
493
568
|
|
|
494
569
|
# Determine if door close notifications are available for the given
|
|
495
570
|
# sensor
|
|
@@ -499,7 +574,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
499
574
|
# The condition intentionally doesn't account for cord sensors of
|
|
500
575
|
# subtype door, since those won't send door open/close alerts, only
|
|
501
576
|
# notifications
|
|
502
|
-
sensor_is_door = sensor.type ==
|
|
577
|
+
sensor_is_door = sensor.type == G90PeripheralTypes.DOOR
|
|
503
578
|
|
|
504
579
|
# Alarm panel could emit door close alerts (if enabled) for sensors
|
|
505
580
|
# of type `door`, and such event will be used to reset the
|
|
@@ -519,21 +594,28 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
519
594
|
reset_sensor_occupancy, sensor)
|
|
520
595
|
|
|
521
596
|
# Invoke per-sensor callback if provided
|
|
522
|
-
|
|
597
|
+
sensor.state_callback.invoke(occupancy)
|
|
523
598
|
|
|
524
599
|
# Invoke global callback if provided
|
|
525
|
-
|
|
600
|
+
self._sensor_cb.invoke(idx, name, occupancy)
|
|
526
601
|
|
|
527
602
|
@property
|
|
528
|
-
def sensor_callback(self) ->
|
|
603
|
+
def sensor_callback(self) -> G90CallbackList[SensorCallback]:
|
|
529
604
|
"""
|
|
530
605
|
Sensor activity callback, which is invoked when sensor activates.
|
|
606
|
+
|
|
607
|
+
Setting the property will add the callback to the list of (retained for
|
|
608
|
+
compatilibity with earlier package versions), or
|
|
609
|
+
:class:`.G90CallbackList` instance could be accessed over the
|
|
610
|
+
property - `G90Alarm(...).sensor_callback.add(callback)` or
|
|
611
|
+
`G90Alarm(...).sensor_callback.remove(callback)` methods could be used
|
|
612
|
+
to add or remove the callback, respectively.
|
|
531
613
|
"""
|
|
532
614
|
return self._sensor_cb
|
|
533
615
|
|
|
534
616
|
@sensor_callback.setter
|
|
535
617
|
def sensor_callback(self, value: SensorCallback) -> None:
|
|
536
|
-
self._sensor_cb
|
|
618
|
+
self._sensor_cb.add(value)
|
|
537
619
|
|
|
538
620
|
async def on_door_open_close(
|
|
539
621
|
self, event_id: int, zone_name: str, is_open: bool
|
|
@@ -552,22 +634,24 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
552
634
|
# closed, since the notifications aren't sent for such events
|
|
553
635
|
await self.on_sensor_activity(event_id, zone_name, is_open)
|
|
554
636
|
# Invoke user specified callback if any
|
|
555
|
-
|
|
556
|
-
self._door_open_close_cb, event_id, zone_name, is_open
|
|
557
|
-
)
|
|
637
|
+
self._door_open_close_cb.invoke(event_id, zone_name, is_open)
|
|
558
638
|
|
|
559
639
|
@property
|
|
560
|
-
def door_open_close_callback(
|
|
640
|
+
def door_open_close_callback(
|
|
641
|
+
self
|
|
642
|
+
) -> G90CallbackList[DoorOpenCloseCallback]:
|
|
561
643
|
"""
|
|
562
644
|
The door open/close callback, which is invoked when door
|
|
563
645
|
is opened or closed (if corresponding alert is configured on the
|
|
564
646
|
device).
|
|
647
|
+
|
|
648
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
565
649
|
"""
|
|
566
650
|
return self._door_open_close_cb
|
|
567
651
|
|
|
568
652
|
@door_open_close_callback.setter
|
|
569
653
|
def door_open_close_callback(self, value: DoorOpenCloseCallback) -> None:
|
|
570
|
-
self._door_open_close_cb
|
|
654
|
+
self._door_open_close_cb.add(value)
|
|
571
655
|
|
|
572
656
|
async def on_armdisarm(self, state: G90ArmDisarmTypes) -> None:
|
|
573
657
|
"""
|
|
@@ -596,19 +680,21 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
596
680
|
# pylint: disable=protected-access
|
|
597
681
|
sensor._set_door_open_when_arming(False)
|
|
598
682
|
|
|
599
|
-
|
|
683
|
+
self._armdisarm_cb.invoke(state)
|
|
600
684
|
|
|
601
685
|
@property
|
|
602
|
-
def armdisarm_callback(self) ->
|
|
686
|
+
def armdisarm_callback(self) -> G90CallbackList[ArmDisarmCallback]:
|
|
603
687
|
"""
|
|
604
688
|
The device arm/disarm callback, which is invoked when device state
|
|
605
689
|
changes.
|
|
690
|
+
|
|
691
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
606
692
|
"""
|
|
607
693
|
return self._armdisarm_cb
|
|
608
694
|
|
|
609
695
|
@armdisarm_callback.setter
|
|
610
696
|
def armdisarm_callback(self, value: ArmDisarmCallback) -> None:
|
|
611
|
-
self._armdisarm_cb
|
|
697
|
+
self._armdisarm_cb.add(value)
|
|
612
698
|
|
|
613
699
|
async def on_alarm(
|
|
614
700
|
self, event_id: int, zone_name: str, is_tampered: bool
|
|
@@ -643,26 +729,26 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
643
729
|
sensor._set_tampered(True)
|
|
644
730
|
|
|
645
731
|
# Invoke per-sensor callback if provided
|
|
646
|
-
|
|
732
|
+
sensor.tamper_callback.invoke()
|
|
647
733
|
|
|
648
734
|
# Invoke global tamper callback if provided and the sensor is tampered
|
|
649
735
|
if is_tampered:
|
|
650
|
-
|
|
736
|
+
self._tamper_cb.invoke(event_id, zone_name)
|
|
651
737
|
|
|
652
|
-
|
|
653
|
-
self._alarm_cb, event_id, zone_name, extra_data
|
|
654
|
-
)
|
|
738
|
+
self._alarm_cb.invoke(event_id, zone_name, extra_data)
|
|
655
739
|
|
|
656
740
|
@property
|
|
657
|
-
def alarm_callback(self) ->
|
|
741
|
+
def alarm_callback(self) -> G90CallbackList[AlarmCallback]:
|
|
658
742
|
"""
|
|
659
743
|
The device alarm callback, which is invoked when device alarm triggers.
|
|
744
|
+
|
|
745
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
660
746
|
"""
|
|
661
747
|
return self._alarm_cb
|
|
662
748
|
|
|
663
749
|
@alarm_callback.setter
|
|
664
750
|
def alarm_callback(self, value: AlarmCallback) -> None:
|
|
665
|
-
self._alarm_cb
|
|
751
|
+
self._alarm_cb.add(value)
|
|
666
752
|
|
|
667
753
|
async def on_low_battery(self, event_id: int, zone_name: str) -> None:
|
|
668
754
|
"""
|
|
@@ -682,21 +768,23 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
682
768
|
# pylint: disable=protected-access
|
|
683
769
|
sensor._set_low_battery(True)
|
|
684
770
|
# Invoke per-sensor callback if provided
|
|
685
|
-
|
|
771
|
+
sensor.low_battery_callback.invoke()
|
|
686
772
|
|
|
687
|
-
|
|
773
|
+
self._low_battery_cb.invoke(event_id, zone_name)
|
|
688
774
|
|
|
689
775
|
@property
|
|
690
|
-
def low_battery_callback(self) ->
|
|
776
|
+
def low_battery_callback(self) -> G90CallbackList[LowBatteryCallback]:
|
|
691
777
|
"""
|
|
692
778
|
Low battery callback, which is invoked when sensor reports the
|
|
693
779
|
condition.
|
|
780
|
+
|
|
781
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
694
782
|
"""
|
|
695
783
|
return self._low_battery_cb
|
|
696
784
|
|
|
697
785
|
@low_battery_callback.setter
|
|
698
786
|
def low_battery_callback(self, value: LowBatteryCallback) -> None:
|
|
699
|
-
self._low_battery_cb
|
|
787
|
+
self._low_battery_cb.add(value)
|
|
700
788
|
|
|
701
789
|
async def on_sos(
|
|
702
790
|
self, event_id: int, zone_name: str, is_host_sos: bool
|
|
@@ -714,7 +802,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
714
802
|
(host)
|
|
715
803
|
"""
|
|
716
804
|
_LOGGER.debug('on_sos: %s %s %s', event_id, zone_name, is_host_sos)
|
|
717
|
-
|
|
805
|
+
self._sos_cb.invoke(event_id, zone_name, is_host_sos)
|
|
718
806
|
|
|
719
807
|
# Also report the event as alarm for unification, hard-coding the
|
|
720
808
|
# sensor name in case of host SOS
|
|
@@ -731,15 +819,17 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
731
819
|
)
|
|
732
820
|
|
|
733
821
|
@property
|
|
734
|
-
def sos_callback(self) ->
|
|
822
|
+
def sos_callback(self) -> G90CallbackList[SosCallback]:
|
|
735
823
|
"""
|
|
736
824
|
SOS callback, which is invoked when SOS alert is triggered.
|
|
825
|
+
|
|
826
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
737
827
|
"""
|
|
738
828
|
return self._sos_cb
|
|
739
829
|
|
|
740
830
|
@sos_callback.setter
|
|
741
831
|
def sos_callback(self, value: SosCallback) -> None:
|
|
742
|
-
self._sos_cb
|
|
832
|
+
self._sos_cb.add(value)
|
|
743
833
|
|
|
744
834
|
async def on_remote_button_press(
|
|
745
835
|
self, event_id: int, zone_name: str, button: G90RemoteButtonStates
|
|
@@ -757,9 +847,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
757
847
|
_LOGGER.debug(
|
|
758
848
|
'on_remote_button_press: %s %s %s', event_id, zone_name, button
|
|
759
849
|
)
|
|
760
|
-
|
|
761
|
-
self._remote_button_press_cb, event_id, zone_name, button
|
|
762
|
-
)
|
|
850
|
+
self._remote_button_press_cb.invoke(event_id, zone_name, button)
|
|
763
851
|
|
|
764
852
|
# Also report the event as sensor activity for unification (remote is
|
|
765
853
|
# just a special type of the sensor)
|
|
@@ -768,10 +856,12 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
768
856
|
@property
|
|
769
857
|
def remote_button_press_callback(
|
|
770
858
|
self
|
|
771
|
-
) ->
|
|
859
|
+
) -> G90CallbackList[RemoteButtonPressCallback]:
|
|
772
860
|
"""
|
|
773
861
|
Remote button press callback, which is invoked when remote button is
|
|
774
862
|
pressed.
|
|
863
|
+
|
|
864
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
775
865
|
"""
|
|
776
866
|
return self._remote_button_press_cb
|
|
777
867
|
|
|
@@ -779,7 +869,7 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
779
869
|
def remote_button_press_callback(
|
|
780
870
|
self, value: RemoteButtonPressCallback
|
|
781
871
|
) -> None:
|
|
782
|
-
self._remote_button_press_cb
|
|
872
|
+
self._remote_button_press_cb.add(value)
|
|
783
873
|
|
|
784
874
|
async def on_door_open_when_arming(
|
|
785
875
|
self, event_id: int, zone_name: str
|
|
@@ -802,17 +892,19 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
802
892
|
# pylint: disable=protected-access
|
|
803
893
|
sensor._set_door_open_when_arming(True)
|
|
804
894
|
# Invoke per-sensor callback if provided
|
|
805
|
-
|
|
895
|
+
sensor.door_open_when_arming_callback.invoke()
|
|
806
896
|
|
|
807
|
-
|
|
897
|
+
self._door_open_when_arming_cb.invoke(event_id, zone_name)
|
|
808
898
|
|
|
809
899
|
@property
|
|
810
900
|
def door_open_when_arming_callback(
|
|
811
901
|
self
|
|
812
|
-
) ->
|
|
902
|
+
) -> G90CallbackList[DoorOpenWhenArmingCallback]:
|
|
813
903
|
"""
|
|
814
904
|
Door open when arming callback, which is invoked when sensor reports
|
|
815
905
|
the condition.
|
|
906
|
+
|
|
907
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
816
908
|
"""
|
|
817
909
|
return self._door_open_when_arming_cb
|
|
818
910
|
|
|
@@ -820,10 +912,10 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
820
912
|
def door_open_when_arming_callback(
|
|
821
913
|
self, value: DoorOpenWhenArmingCallback
|
|
822
914
|
) -> None:
|
|
823
|
-
self._door_open_when_arming_cb
|
|
915
|
+
self._door_open_when_arming_cb.add(value)
|
|
824
916
|
|
|
825
917
|
@property
|
|
826
|
-
|
|
918
|
+
def tamper_callback(self) -> G90CallbackList[TamperCallback]:
|
|
827
919
|
"""
|
|
828
920
|
Tamper callback, which is invoked when sensor reports the condition.
|
|
829
921
|
"""
|
|
@@ -831,7 +923,109 @@ class G90Alarm(G90NotificationProtocol):
|
|
|
831
923
|
|
|
832
924
|
@tamper_callback.setter
|
|
833
925
|
def tamper_callback(self, value: TamperCallback) -> None:
|
|
834
|
-
self._tamper_cb
|
|
926
|
+
self._tamper_cb.add(value)
|
|
927
|
+
|
|
928
|
+
async def on_sensor_change(
|
|
929
|
+
self, sensor_idx: int, sensor_name: str, added: bool
|
|
930
|
+
) -> None:
|
|
931
|
+
"""
|
|
932
|
+
Invoked when sensor is added or removed from the device.
|
|
933
|
+
|
|
934
|
+
There is no user-visible callback assoiciated with this method, those
|
|
935
|
+
will be handled by `on_sensor_list_change()` method.
|
|
936
|
+
|
|
937
|
+
Please note the method is for internal use by the class.
|
|
938
|
+
|
|
939
|
+
:param sensor_idx: The index of the sensor being added/removed.
|
|
940
|
+
:param sensor_name: The name of the sensor.
|
|
941
|
+
:param added: Flag indicating if the sensor is added or removed
|
|
942
|
+
"""
|
|
943
|
+
_LOGGER.debug(
|
|
944
|
+
'on_sensor_change: idx=%s name=%s added=%s',
|
|
945
|
+
sensor_idx, sensor_name, added
|
|
946
|
+
)
|
|
947
|
+
|
|
948
|
+
# Invoke internal callback for sensor list to finish the registration
|
|
949
|
+
# process
|
|
950
|
+
G90Callback.invoke(
|
|
951
|
+
self._sensors.sensor_change_callback,
|
|
952
|
+
sensor_idx, sensor_name, added
|
|
953
|
+
)
|
|
954
|
+
|
|
955
|
+
@property
|
|
956
|
+
def sensor_list_change_callback(
|
|
957
|
+
self
|
|
958
|
+
) -> G90CallbackList[ListChangeCallback[G90Sensor]]:
|
|
959
|
+
"""
|
|
960
|
+
Sensor list change callback, which is invoked when sensor list
|
|
961
|
+
changes.
|
|
962
|
+
|
|
963
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
964
|
+
"""
|
|
965
|
+
return self._sensor_list_change_cb
|
|
966
|
+
|
|
967
|
+
@sensor_list_change_callback.setter
|
|
968
|
+
def sensor_list_change_callback(
|
|
969
|
+
self, value: ListChangeCallback[G90Sensor]
|
|
970
|
+
) -> None:
|
|
971
|
+
self._sensor_list_change_cb.add(value)
|
|
972
|
+
|
|
973
|
+
async def on_sensor_list_change(
|
|
974
|
+
self, sensor: G90Sensor, added: bool
|
|
975
|
+
) -> None:
|
|
976
|
+
"""
|
|
977
|
+
Invoked when sensor list is changed.
|
|
978
|
+
|
|
979
|
+
Fires corresponding callback if set by the user with
|
|
980
|
+
:attr:`.sensor_list_change_callback`.
|
|
981
|
+
Please note the method is for internal use by the class.
|
|
982
|
+
|
|
983
|
+
:param sensor: The sensor being added or removed
|
|
984
|
+
:param added: Flag indicating if the sensor is added or removed
|
|
985
|
+
"""
|
|
986
|
+
_LOGGER.debug(
|
|
987
|
+
'on_sensor_list_change: %s added=%s', repr(sensor), added
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
self._sensor_list_change_cb.invoke(sensor, added)
|
|
991
|
+
|
|
992
|
+
@property
|
|
993
|
+
def device_list_change_callback(
|
|
994
|
+
self
|
|
995
|
+
) -> G90CallbackList[ListChangeCallback[G90Device]]:
|
|
996
|
+
"""
|
|
997
|
+
Device list change callback, which is invoked when device list
|
|
998
|
+
changes.
|
|
999
|
+
|
|
1000
|
+
.. seealso:: :attr:`.sensor_callback` for compatiblity notes
|
|
1001
|
+
"""
|
|
1002
|
+
return self._device_list_change_cb
|
|
1003
|
+
|
|
1004
|
+
@device_list_change_callback.setter
|
|
1005
|
+
def device_list_change_callback(
|
|
1006
|
+
self, value: ListChangeCallback[G90Device]
|
|
1007
|
+
) -> None:
|
|
1008
|
+
self._device_list_change_cb.add(value)
|
|
1009
|
+
|
|
1010
|
+
async def on_device_list_change(
|
|
1011
|
+
self, device: G90Device, added: bool
|
|
1012
|
+
) -> None:
|
|
1013
|
+
"""
|
|
1014
|
+
Invoked when device list is changed.
|
|
1015
|
+
|
|
1016
|
+
Fires corresponding callback if set by the user with
|
|
1017
|
+
:attr:`.device_list_change_callback`.
|
|
1018
|
+
|
|
1019
|
+
Please note the method is for internal use by the class.
|
|
1020
|
+
|
|
1021
|
+
:param device: The device being added or removed
|
|
1022
|
+
:param added: Flag indicating if the device is added or removed
|
|
1023
|
+
"""
|
|
1024
|
+
_LOGGER.debug(
|
|
1025
|
+
'on_device_list_change: %s added=%s', repr(device), added
|
|
1026
|
+
)
|
|
1027
|
+
|
|
1028
|
+
self._device_list_change_cb.invoke(device, added)
|
|
835
1029
|
|
|
836
1030
|
async def listen_notifications(self) -> None:
|
|
837
1031
|
"""
|
pyg90alarm/callback.py
CHANGED
|
@@ -25,17 +25,20 @@ from __future__ import annotations
|
|
|
25
25
|
import asyncio
|
|
26
26
|
from functools import (partial, wraps)
|
|
27
27
|
from asyncio import Task
|
|
28
|
-
from typing import
|
|
28
|
+
from typing import (
|
|
29
|
+
Any, Callable, Coroutine, cast, Optional, Union, TypeVar, Generic
|
|
30
|
+
)
|
|
29
31
|
import logging
|
|
30
32
|
|
|
31
|
-
_LOGGER = logging.getLogger(__name__)
|
|
32
|
-
|
|
33
33
|
Callback = Optional[
|
|
34
34
|
Union[
|
|
35
35
|
Callable[..., None],
|
|
36
36
|
Callable[..., Coroutine[None, None, None]],
|
|
37
37
|
]
|
|
38
38
|
]
|
|
39
|
+
T = TypeVar('T', bound=Callback)
|
|
40
|
+
|
|
41
|
+
_LOGGER = logging.getLogger(__name__)
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
class G90Callback:
|
|
@@ -106,3 +109,38 @@ class G90Callback:
|
|
|
106
109
|
"""
|
|
107
110
|
loop = asyncio.get_running_loop()
|
|
108
111
|
loop.call_later(delay, partial(callback, *args, **kwargs))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class G90CallbackList(Generic[T]):
|
|
115
|
+
"""
|
|
116
|
+
Implements a list of callbacks.
|
|
117
|
+
"""
|
|
118
|
+
def __init__(self) -> None:
|
|
119
|
+
self._callbacks: list[T] = []
|
|
120
|
+
|
|
121
|
+
def add(self, callback: T) -> None:
|
|
122
|
+
"""
|
|
123
|
+
Adds a callback to the list.
|
|
124
|
+
"""
|
|
125
|
+
if callback and callback not in self._callbacks:
|
|
126
|
+
self._callbacks.append(callback)
|
|
127
|
+
|
|
128
|
+
def remove(self, callback: T) -> None:
|
|
129
|
+
"""
|
|
130
|
+
Removes a callback from the list.
|
|
131
|
+
"""
|
|
132
|
+
if callback in self._callbacks:
|
|
133
|
+
self._callbacks.remove(callback)
|
|
134
|
+
|
|
135
|
+
def clear(self) -> None:
|
|
136
|
+
"""
|
|
137
|
+
Clears the list of callbacks.
|
|
138
|
+
"""
|
|
139
|
+
self._callbacks.clear()
|
|
140
|
+
|
|
141
|
+
def invoke(self, *args: Any, **kwargs: Any) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Invokes all callbacks in the list.
|
|
144
|
+
"""
|
|
145
|
+
for callback in self._callbacks:
|
|
146
|
+
G90Callback.invoke(callback, *args, **kwargs)
|