pyg90alarm 1.10.0__tar.gz → 1.11.0__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.
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/.github/workflows/main.yml +3 -2
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/PKG-INFO +7 -2
- pyg90alarm-1.11.0/docs/requirements.txt +10 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/pyproject.toml +5 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/alarm.py +9 -13
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/base_cmd.py +13 -20
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/const.py +1 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/definitions/sensors.py +241 -1
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/device_notifications.py +11 -16
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/targeted_discovery.py +1 -1
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm.egg-info/PKG-INFO +7 -2
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm.egg-info/SOURCES.txt +2 -2
- pyg90alarm-1.11.0/tests/conftest.py +66 -0
- pyg90alarm-1.11.0/tests/device_mock.py +264 -0
- pyg90alarm-1.11.0/tests/test_alarm.py +679 -0
- pyg90alarm-1.11.0/tests/test_base_commands.py +188 -0
- pyg90alarm-1.11.0/tests/test_callback.py +27 -0
- pyg90alarm-1.11.0/tests/test_discovery.py +87 -0
- pyg90alarm-1.11.0/tests/test_notifications.py +245 -0
- pyg90alarm-1.11.0/tests/test_paginated_commands.py +83 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/tox.ini +6 -5
- pyg90alarm-1.10.0/docs/requirements.txt +0 -4
- pyg90alarm-1.10.0/tests/__init__.py +0 -11
- pyg90alarm-1.10.0/tests/fixtures.py +0 -31
- pyg90alarm-1.10.0/tests/test_alarm.py +0 -669
- pyg90alarm-1.10.0/tests/test_base_commands.py +0 -131
- pyg90alarm-1.10.0/tests/test_callback.py +0 -29
- pyg90alarm-1.10.0/tests/test_discovery.py +0 -105
- pyg90alarm-1.10.0/tests/test_notifications.py +0 -238
- pyg90alarm-1.10.0/tests/test_paginated_commands.py +0 -75
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/.github/CODEOWNERS +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/.gitignore +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/.pylintrc +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/.readthedocs.yaml +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/LICENSE +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/MANIFEST.in +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/README.rst +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/.DS_Store +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/.gitignore +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/api-docs.rst +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/conf.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/index.rst +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/docs/protocol.rst +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/setup.cfg +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/setup.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/sonar-project.properties +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/__init__.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/callback.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/config.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/definitions/__init__.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/discovery.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/entities/__init__.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/entities/device.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/entities/sensor.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/exceptions.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/history.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/host_info.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/host_status.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/paginated_cmd.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/paginated_result.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm/user_data_crc.py +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm.egg-info/dependency_links.txt +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm.egg-info/requires.txt +0 -0
- {pyg90alarm-1.10.0 → pyg90alarm-1.11.0}/src/pyg90alarm.egg-info/top_level.txt +0 -0
|
@@ -28,6 +28,9 @@ jobs:
|
|
|
28
28
|
- os: ubuntu-latest
|
|
29
29
|
python: '3.10'
|
|
30
30
|
toxenv: py
|
|
31
|
+
- os: ubuntu-latest
|
|
32
|
+
python: '3.11'
|
|
33
|
+
toxenv: py
|
|
31
34
|
runs-on: ${{ matrix.os }}
|
|
32
35
|
steps:
|
|
33
36
|
- name: Checkout the code
|
|
@@ -45,8 +48,6 @@ jobs:
|
|
|
45
48
|
python -m pip install --upgrade setuptools pip tox virtualenv coverage
|
|
46
49
|
- name: Run the tests
|
|
47
50
|
run: tox -e ${{ matrix.toxenv }}
|
|
48
|
-
- name: Combine Coverage reports
|
|
49
|
-
run: coverage combine
|
|
50
51
|
- name: Generage Coverage combined XML report
|
|
51
52
|
run: coverage xml
|
|
52
53
|
- name: Determine package version
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyg90alarm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.11.0
|
|
4
4
|
Summary: G90 Alarm system protocol
|
|
5
5
|
Home-page: https://github.com/hostcc/pyg90alarm
|
|
6
6
|
Author: Ilia Sotnikov
|
|
@@ -22,10 +22,15 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
23
|
Requires-Python: >=3.7, <4
|
|
24
24
|
Description-Content-Type: text/x-rst
|
|
25
|
+
License-File: LICENSE
|
|
25
26
|
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: check-manifest; extra == "dev"
|
|
26
28
|
Provides-Extra: test
|
|
29
|
+
Requires-Dist: coverage; extra == "test"
|
|
30
|
+
Requires-Dist: asynctest; extra == "test"
|
|
27
31
|
Provides-Extra: docs
|
|
28
|
-
|
|
32
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
33
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
29
34
|
|
|
30
35
|
.. image:: https://github.com/hostcc/pyg90alarm/actions/workflows/main.yml/badge.svg?branch=master
|
|
31
36
|
:target: https://github.com/hostcc/pyg90alarm/tree/master
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
sphinx-rtd-theme
|
|
2
|
+
enum-tools[sphinx]
|
|
3
|
+
pygments>=2.15.0 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
4
|
+
sphinx>=3.3.0 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
5
|
+
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
6
|
+
certifi>=2023.7.22 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
7
|
+
requests>=2.32.0 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
8
|
+
jinja2>=3.1.4 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
9
|
+
requests>=2.31.0 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
10
|
+
idna>=3.7 # not directly required, pinned by Snyk to avoid a vulnerability
|
|
@@ -54,6 +54,7 @@ from .const import (
|
|
|
54
54
|
G90Commands, REMOTE_PORT,
|
|
55
55
|
REMOTE_TARGETED_DISCOVERY_PORT,
|
|
56
56
|
LOCAL_TARGETED_DISCOVERY_PORT,
|
|
57
|
+
NOTIFICATIONS_PORT,
|
|
57
58
|
G90ArmDisarmTypes,
|
|
58
59
|
)
|
|
59
60
|
from .base_cmd import G90BaseCommand
|
|
@@ -87,23 +88,18 @@ class G90Alarm: # pylint: disable=too-many-public-methods
|
|
|
87
88
|
protocol commands on WiFi interface, currently the devices don't allow it
|
|
88
89
|
to be customized
|
|
89
90
|
:type port: int, optional
|
|
90
|
-
:param sock: The existing socket to operate on, instead of
|
|
91
|
-
creating one internally. Primarily used by the tests to mock the network
|
|
92
|
-
traffic
|
|
93
|
-
:type sock: socket.socket or None, optional
|
|
94
91
|
:param reset_occupancy_interval: The interval upon that the sensors are
|
|
95
92
|
simulated to go into inactive state.
|
|
96
93
|
:type reset_occupancy_interval: int, optional
|
|
97
94
|
"""
|
|
98
95
|
# pylint: disable=too-many-instance-attributes
|
|
99
|
-
def __init__(self, host, port=REMOTE_PORT,
|
|
96
|
+
def __init__(self, host, port=REMOTE_PORT,
|
|
100
97
|
reset_occupancy_interval=3):
|
|
101
98
|
self._host = host
|
|
102
99
|
self._port = port
|
|
103
100
|
self._sensors = []
|
|
104
101
|
self._devices = []
|
|
105
102
|
self._notifications = None
|
|
106
|
-
self._sock = sock
|
|
107
103
|
self._sensor_cb = None
|
|
108
104
|
self._armdisarm_cb = None
|
|
109
105
|
self._door_open_close_cb = None
|
|
@@ -124,7 +120,7 @@ class G90Alarm: # pylint: disable=too-many-public-methods
|
|
|
124
120
|
command invocation
|
|
125
121
|
"""
|
|
126
122
|
cmd = await G90BaseCommand(
|
|
127
|
-
self._host, self._port, code, data
|
|
123
|
+
self._host, self._port, code, data).process()
|
|
128
124
|
return cmd.result
|
|
129
125
|
|
|
130
126
|
def paginated_result(self, code, start=1, end=None):
|
|
@@ -141,7 +137,7 @@ class G90Alarm: # pylint: disable=too-many-public-methods
|
|
|
141
137
|
yields :class:`.G90PaginatedResponse` instance
|
|
142
138
|
"""
|
|
143
139
|
return G90PaginatedResult(
|
|
144
|
-
self._host, self._port, code, start, end
|
|
140
|
+
self._host, self._port, code, start, end
|
|
145
141
|
).process()
|
|
146
142
|
|
|
147
143
|
@classmethod
|
|
@@ -585,19 +581,19 @@ class G90Alarm: # pylint: disable=too-many-public-methods
|
|
|
585
581
|
def alarm_callback(self, value):
|
|
586
582
|
self._alarm_cb = value
|
|
587
583
|
|
|
588
|
-
async def listen_device_notifications(
|
|
584
|
+
async def listen_device_notifications(
|
|
585
|
+
self, host='0.0.0.0', port=NOTIFICATIONS_PORT
|
|
586
|
+
):
|
|
589
587
|
"""
|
|
590
588
|
Starts internal listener for device notifications/alerts.
|
|
591
589
|
|
|
592
|
-
:param sock: socket instance to listen on, mostly used by tests
|
|
593
|
-
:type: socket.socket
|
|
594
590
|
"""
|
|
595
591
|
self._notifications = G90DeviceNotifications(
|
|
592
|
+
host=host, port=port,
|
|
596
593
|
sensor_cb=self._internal_sensor_cb,
|
|
597
594
|
door_open_close_cb=self._internal_door_open_close_cb,
|
|
598
595
|
armdisarm_cb=self._internal_armdisarm_cb,
|
|
599
|
-
alarm_cb=self._internal_alarm_cb
|
|
600
|
-
sock=sock)
|
|
596
|
+
alarm_cb=self._internal_alarm_cb)
|
|
601
597
|
await self._notifications.listen()
|
|
602
598
|
|
|
603
599
|
def close_device_notifications(self):
|
|
@@ -110,7 +110,7 @@ class G90BaseCommand:
|
|
|
110
110
|
|
|
111
111
|
def __init__(self, host, port, code,
|
|
112
112
|
data=None, local_port=None,
|
|
113
|
-
timeout=3.0, retries=3
|
|
113
|
+
timeout=3.0, retries=3):
|
|
114
114
|
"""
|
|
115
115
|
tbd
|
|
116
116
|
"""
|
|
@@ -130,9 +130,8 @@ class G90BaseCommand:
|
|
|
130
130
|
# No whitespace around entities
|
|
131
131
|
separators=(',', ':'))
|
|
132
132
|
self._resp = G90Header()
|
|
133
|
-
self._sock = sock
|
|
134
133
|
|
|
135
|
-
def _proto_factory(self):
|
|
134
|
+
def _proto_factory(self):
|
|
136
135
|
"""
|
|
137
136
|
tbd
|
|
138
137
|
"""
|
|
@@ -147,23 +146,17 @@ class G90BaseCommand:
|
|
|
147
146
|
except AttributeError:
|
|
148
147
|
loop = asyncio.get_event_loop()
|
|
149
148
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
transport, protocol = await loop.create_datagram_endpoint(
|
|
163
|
-
self._proto_factory,
|
|
164
|
-
remote_addr=(self.host, self.port),
|
|
165
|
-
**extra_kwargs,
|
|
166
|
-
allow_broadcast=True)
|
|
149
|
+
_LOGGER.debug('Creating UDP endpoint for %s:%s',
|
|
150
|
+
self.host, self.port)
|
|
151
|
+
extra_kwargs = {}
|
|
152
|
+
if self._local_port:
|
|
153
|
+
extra_kwargs['local_addr'] = ('0.0.0.0', self._local_port)
|
|
154
|
+
|
|
155
|
+
transport, protocol = await loop.create_datagram_endpoint(
|
|
156
|
+
self._proto_factory,
|
|
157
|
+
remote_addr=(self.host, self.port),
|
|
158
|
+
**extra_kwargs,
|
|
159
|
+
allow_broadcast=True)
|
|
167
160
|
|
|
168
161
|
return transport, protocol
|
|
169
162
|
|
|
@@ -475,6 +475,16 @@ SENSOR_DEFINITIONS = [
|
|
|
475
475
|
rwMode=SensorRwMode.READ,
|
|
476
476
|
matchMode=SensorMatchMode.ONLY20BITS
|
|
477
477
|
),
|
|
478
|
+
# Door Sensor WRDS01
|
|
479
|
+
SensorDefinition(
|
|
480
|
+
type=1,
|
|
481
|
+
subtype=3,
|
|
482
|
+
rx=0,
|
|
483
|
+
tx=0,
|
|
484
|
+
private_data='00',
|
|
485
|
+
rwMode=SensorRwMode.READ,
|
|
486
|
+
matchMode=SensorMatchMode.ALL
|
|
487
|
+
),
|
|
478
488
|
# Door Sensor
|
|
479
489
|
SensorDefinition(
|
|
480
490
|
type=1,
|
|
@@ -485,6 +495,96 @@ SENSOR_DEFINITIONS = [
|
|
|
485
495
|
rwMode=SensorRwMode.READ,
|
|
486
496
|
matchMode=SensorMatchMode.ONLY16BITS
|
|
487
497
|
),
|
|
498
|
+
# Glass Break Sensor BLPS
|
|
499
|
+
SensorDefinition(
|
|
500
|
+
type=2,
|
|
501
|
+
subtype=0,
|
|
502
|
+
rx=0,
|
|
503
|
+
tx=0,
|
|
504
|
+
private_data='00',
|
|
505
|
+
rwMode=SensorRwMode.READ,
|
|
506
|
+
matchMode=SensorMatchMode.ALL
|
|
507
|
+
),
|
|
508
|
+
# Gas Detector WGD01
|
|
509
|
+
SensorDefinition(
|
|
510
|
+
type=3,
|
|
511
|
+
subtype=0,
|
|
512
|
+
rx=0,
|
|
513
|
+
tx=0,
|
|
514
|
+
private_data='00',
|
|
515
|
+
rwMode=SensorRwMode.READ,
|
|
516
|
+
matchMode=SensorMatchMode.ALL
|
|
517
|
+
),
|
|
518
|
+
# Smoke Detector WSD02
|
|
519
|
+
SensorDefinition(
|
|
520
|
+
type=4,
|
|
521
|
+
subtype=0,
|
|
522
|
+
rx=0,
|
|
523
|
+
tx=0,
|
|
524
|
+
private_data='00',
|
|
525
|
+
rwMode=SensorRwMode.READ,
|
|
526
|
+
matchMode=SensorMatchMode.ALL
|
|
527
|
+
),
|
|
528
|
+
# Smoke Detector WSD04
|
|
529
|
+
SensorDefinition(
|
|
530
|
+
type=4,
|
|
531
|
+
subtype=1,
|
|
532
|
+
rx=0,
|
|
533
|
+
tx=0,
|
|
534
|
+
private_data='00',
|
|
535
|
+
rwMode=SensorRwMode.READ,
|
|
536
|
+
matchMode=SensorMatchMode.ALL
|
|
537
|
+
),
|
|
538
|
+
# Panic Button WEB01
|
|
539
|
+
SensorDefinition(
|
|
540
|
+
type=5,
|
|
541
|
+
subtype=1,
|
|
542
|
+
rx=0,
|
|
543
|
+
tx=0,
|
|
544
|
+
private_data='00',
|
|
545
|
+
rwMode=SensorRwMode.READ,
|
|
546
|
+
matchMode=SensorMatchMode.ALL
|
|
547
|
+
),
|
|
548
|
+
# Panic Button WEB03
|
|
549
|
+
SensorDefinition(
|
|
550
|
+
type=5,
|
|
551
|
+
subtype=0,
|
|
552
|
+
rx=0,
|
|
553
|
+
tx=0,
|
|
554
|
+
private_data='00',
|
|
555
|
+
rwMode=SensorRwMode.READ,
|
|
556
|
+
matchMode=SensorMatchMode.ALL
|
|
557
|
+
),
|
|
558
|
+
# Shock Sensor WSS01
|
|
559
|
+
SensorDefinition(
|
|
560
|
+
type=6,
|
|
561
|
+
subtype=0,
|
|
562
|
+
rx=0,
|
|
563
|
+
tx=0,
|
|
564
|
+
private_data='00',
|
|
565
|
+
rwMode=SensorRwMode.READ,
|
|
566
|
+
matchMode=SensorMatchMode.ALL
|
|
567
|
+
),
|
|
568
|
+
# Water Detector LSTC02
|
|
569
|
+
SensorDefinition(
|
|
570
|
+
type=7,
|
|
571
|
+
subtype=1,
|
|
572
|
+
rx=0,
|
|
573
|
+
tx=0,
|
|
574
|
+
private_data='',
|
|
575
|
+
rwMode=SensorRwMode.READ,
|
|
576
|
+
matchMode=SensorMatchMode.ALL
|
|
577
|
+
),
|
|
578
|
+
# Water Detector LSTC01
|
|
579
|
+
SensorDefinition(
|
|
580
|
+
type=7,
|
|
581
|
+
subtype=0,
|
|
582
|
+
rx=0,
|
|
583
|
+
tx=0,
|
|
584
|
+
private_data='00',
|
|
585
|
+
rwMode=SensorRwMode.READ,
|
|
586
|
+
matchMode=SensorMatchMode.ALL
|
|
587
|
+
),
|
|
488
588
|
# PIR motion sensor WMS08
|
|
489
589
|
SensorDefinition(
|
|
490
590
|
type=8,
|
|
@@ -505,6 +605,66 @@ SENSOR_DEFINITIONS = [
|
|
|
505
605
|
rwMode=SensorRwMode.READ,
|
|
506
606
|
matchMode=SensorMatchMode.ONLY20BITS
|
|
507
607
|
),
|
|
608
|
+
# PIR motion sensor ODPIR
|
|
609
|
+
SensorDefinition(
|
|
610
|
+
type=8,
|
|
611
|
+
subtype=0,
|
|
612
|
+
rx=0,
|
|
613
|
+
tx=0,
|
|
614
|
+
private_data='00',
|
|
615
|
+
rwMode=SensorRwMode.READ,
|
|
616
|
+
matchMode=SensorMatchMode.ALL
|
|
617
|
+
),
|
|
618
|
+
# PIR motion sensor N650
|
|
619
|
+
SensorDefinition(
|
|
620
|
+
type=8,
|
|
621
|
+
subtype=5,
|
|
622
|
+
rx=0,
|
|
623
|
+
tx=0,
|
|
624
|
+
private_data='00',
|
|
625
|
+
rwMode=SensorRwMode.READ,
|
|
626
|
+
matchMode=SensorMatchMode.ALL
|
|
627
|
+
),
|
|
628
|
+
# PIR motion sensor WPD02
|
|
629
|
+
SensorDefinition(
|
|
630
|
+
type=8,
|
|
631
|
+
subtype=6,
|
|
632
|
+
rx=0,
|
|
633
|
+
tx=0,
|
|
634
|
+
private_data='00',
|
|
635
|
+
rwMode=SensorRwMode.READ,
|
|
636
|
+
matchMode=SensorMatchMode.ALL
|
|
637
|
+
),
|
|
638
|
+
# PIR motion sensor WCMS02
|
|
639
|
+
SensorDefinition(
|
|
640
|
+
type=8,
|
|
641
|
+
subtype=8,
|
|
642
|
+
rx=0,
|
|
643
|
+
tx=0,
|
|
644
|
+
private_data='00',
|
|
645
|
+
rwMode=SensorRwMode.READ,
|
|
646
|
+
matchMode=SensorMatchMode.ALL
|
|
647
|
+
),
|
|
648
|
+
# PIR motion sensor CWMS01
|
|
649
|
+
SensorDefinition(
|
|
650
|
+
type=8,
|
|
651
|
+
subtype=9,
|
|
652
|
+
rx=0,
|
|
653
|
+
tx=0,
|
|
654
|
+
private_data='00',
|
|
655
|
+
rwMode=SensorRwMode.READ,
|
|
656
|
+
matchMode=SensorMatchMode.ALL
|
|
657
|
+
),
|
|
658
|
+
# PIR motion sensor WMS04
|
|
659
|
+
SensorDefinition(
|
|
660
|
+
type=8,
|
|
661
|
+
subtype=11,
|
|
662
|
+
rx=0,
|
|
663
|
+
tx=0,
|
|
664
|
+
private_data='00',
|
|
665
|
+
rwMode=SensorRwMode.READ,
|
|
666
|
+
matchMode=SensorMatchMode.ALL
|
|
667
|
+
),
|
|
508
668
|
# PIR motion sensor WMS07
|
|
509
669
|
SensorDefinition(
|
|
510
670
|
type=8,
|
|
@@ -515,6 +675,66 @@ SENSOR_DEFINITIONS = [
|
|
|
515
675
|
rwMode=SensorRwMode.READ,
|
|
516
676
|
matchMode=SensorMatchMode.ONLY20BITS
|
|
517
677
|
),
|
|
678
|
+
# PIR motion sensor ODPIR03
|
|
679
|
+
SensorDefinition(
|
|
680
|
+
type=8,
|
|
681
|
+
subtype=4,
|
|
682
|
+
rx=0,
|
|
683
|
+
tx=0,
|
|
684
|
+
private_data='00',
|
|
685
|
+
rwMode=SensorRwMode.READ,
|
|
686
|
+
matchMode=SensorMatchMode.ALL
|
|
687
|
+
),
|
|
688
|
+
# PIR motion sensor WPD01
|
|
689
|
+
SensorDefinition(
|
|
690
|
+
type=8,
|
|
691
|
+
subtype=7,
|
|
692
|
+
rx=0,
|
|
693
|
+
tx=0,
|
|
694
|
+
private_data='00',
|
|
695
|
+
rwMode=SensorRwMode.READ,
|
|
696
|
+
matchMode=SensorMatchMode.ALL
|
|
697
|
+
),
|
|
698
|
+
# PIR motion sensor PIR Ceiling
|
|
699
|
+
SensorDefinition(
|
|
700
|
+
type=8,
|
|
701
|
+
subtype=1,
|
|
702
|
+
rx=0,
|
|
703
|
+
tx=0,
|
|
704
|
+
private_data='00',
|
|
705
|
+
rwMode=SensorRwMode.READ,
|
|
706
|
+
matchMode=SensorMatchMode.ALL
|
|
707
|
+
),
|
|
708
|
+
# Beams ABT
|
|
709
|
+
SensorDefinition(
|
|
710
|
+
type=9,
|
|
711
|
+
subtype=0,
|
|
712
|
+
rx=0,
|
|
713
|
+
tx=0,
|
|
714
|
+
private_data='00',
|
|
715
|
+
rwMode=SensorRwMode.READ,
|
|
716
|
+
matchMode=SensorMatchMode.ALL
|
|
717
|
+
),
|
|
718
|
+
# Beams ABE
|
|
719
|
+
SensorDefinition(
|
|
720
|
+
type=9,
|
|
721
|
+
subtype=1,
|
|
722
|
+
rx=0,
|
|
723
|
+
tx=0,
|
|
724
|
+
private_data='00',
|
|
725
|
+
rwMode=SensorRwMode.READ,
|
|
726
|
+
matchMode=SensorMatchMode.ALL
|
|
727
|
+
),
|
|
728
|
+
# Beams ABH
|
|
729
|
+
SensorDefinition(
|
|
730
|
+
type=9,
|
|
731
|
+
subtype=2,
|
|
732
|
+
rx=0,
|
|
733
|
+
tx=0,
|
|
734
|
+
private_data='00',
|
|
735
|
+
rwMode=SensorRwMode.READ,
|
|
736
|
+
matchMode=SensorMatchMode.ALL
|
|
737
|
+
),
|
|
518
738
|
# Remote RMC08
|
|
519
739
|
SensorDefinition(
|
|
520
740
|
type=10,
|
|
@@ -565,6 +785,16 @@ SENSOR_DEFINITIONS = [
|
|
|
565
785
|
rwMode=SensorRwMode.READ,
|
|
566
786
|
matchMode=SensorMatchMode.ONLY20BITS
|
|
567
787
|
),
|
|
788
|
+
# Door Bell WDB
|
|
789
|
+
SensorDefinition(
|
|
790
|
+
type=12,
|
|
791
|
+
subtype=1,
|
|
792
|
+
rx=0,
|
|
793
|
+
tx=0,
|
|
794
|
+
private_data='00',
|
|
795
|
+
rwMode=SensorRwMode.READ,
|
|
796
|
+
matchMode=SensorMatchMode.ALL
|
|
797
|
+
),
|
|
568
798
|
# TouchID Detector
|
|
569
799
|
SensorDefinition(
|
|
570
800
|
type=13,
|
|
@@ -595,7 +825,17 @@ SENSOR_DEFINITIONS = [
|
|
|
595
825
|
rwMode=SensorRwMode.READ,
|
|
596
826
|
matchMode=SensorMatchMode.ONLY16BITS
|
|
597
827
|
),
|
|
598
|
-
#
|
|
828
|
+
# Sub Host SS08S
|
|
829
|
+
SensorDefinition(
|
|
830
|
+
type=16,
|
|
831
|
+
subtype=0,
|
|
832
|
+
rx=0,
|
|
833
|
+
tx=0,
|
|
834
|
+
private_data='00',
|
|
835
|
+
rwMode=SensorRwMode.READ,
|
|
836
|
+
matchMode=SensorMatchMode.ALL
|
|
837
|
+
),
|
|
838
|
+
# Gas Valve Detector WGD02
|
|
599
839
|
SensorDefinition(
|
|
600
840
|
type=18,
|
|
601
841
|
subtype=0,
|
|
@@ -36,6 +36,7 @@ from .const import (
|
|
|
36
36
|
G90AlertSources,
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
+
|
|
39
40
|
_LOGGER = logging.getLogger(__name__)
|
|
40
41
|
|
|
41
42
|
|
|
@@ -232,16 +233,17 @@ class G90DeviceNotifications:
|
|
|
232
233
|
"""
|
|
233
234
|
tbd
|
|
234
235
|
"""
|
|
235
|
-
def __init__(self, port
|
|
236
|
-
|
|
236
|
+
def __init__(self, port, host,
|
|
237
|
+
armdisarm_cb=None, sensor_cb=None,
|
|
238
|
+
door_open_close_cb=None, alarm_cb=None):
|
|
237
239
|
# pylint: disable=too-many-arguments
|
|
238
240
|
self._notification_transport = None
|
|
241
|
+
self._host = host
|
|
239
242
|
self._port = port
|
|
240
243
|
self._armdisarm_cb = armdisarm_cb
|
|
241
244
|
self._sensor_cb = sensor_cb
|
|
242
245
|
self._door_open_close_cb = door_open_close_cb
|
|
243
246
|
self._alarm_cb = alarm_cb
|
|
244
|
-
self._sock = sock
|
|
245
247
|
|
|
246
248
|
def proto_factory(self):
|
|
247
249
|
"""
|
|
@@ -263,19 +265,12 @@ class G90DeviceNotifications:
|
|
|
263
265
|
except AttributeError:
|
|
264
266
|
loop = asyncio.get_event_loop()
|
|
265
267
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
else:
|
|
273
|
-
_LOGGER.debug('Creating UDP endpoint for 0.0.0.0:%s',
|
|
274
|
-
self._port)
|
|
275
|
-
(self._notification_transport,
|
|
276
|
-
_protocol) = await loop.create_datagram_endpoint(
|
|
277
|
-
self.proto_factory,
|
|
278
|
-
local_addr=('0.0.0.0', self._port))
|
|
268
|
+
_LOGGER.debug('Creating UDP endpoint for %s:%s',
|
|
269
|
+
self._host, self._port)
|
|
270
|
+
(self._notification_transport,
|
|
271
|
+
_protocol) = await loop.create_datagram_endpoint(
|
|
272
|
+
self.proto_factory,
|
|
273
|
+
local_addr=(self._host, self._port))
|
|
279
274
|
|
|
280
275
|
def close(self):
|
|
281
276
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyg90alarm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.11.0
|
|
4
4
|
Summary: G90 Alarm system protocol
|
|
5
5
|
Home-page: https://github.com/hostcc/pyg90alarm
|
|
6
6
|
Author: Ilia Sotnikov
|
|
@@ -22,10 +22,15 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
23
|
Requires-Python: >=3.7, <4
|
|
24
24
|
Description-Content-Type: text/x-rst
|
|
25
|
+
License-File: LICENSE
|
|
25
26
|
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: check-manifest; extra == "dev"
|
|
26
28
|
Provides-Extra: test
|
|
29
|
+
Requires-Dist: coverage; extra == "test"
|
|
30
|
+
Requires-Dist: asynctest; extra == "test"
|
|
27
31
|
Provides-Extra: docs
|
|
28
|
-
|
|
32
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
33
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
29
34
|
|
|
30
35
|
.. image:: https://github.com/hostcc/pyg90alarm/actions/workflows/main.yml/badge.svg?branch=master
|
|
31
36
|
:target: https://github.com/hostcc/pyg90alarm/tree/master
|
|
@@ -44,8 +44,8 @@ src/pyg90alarm/definitions/sensors.py
|
|
|
44
44
|
src/pyg90alarm/entities/__init__.py
|
|
45
45
|
src/pyg90alarm/entities/device.py
|
|
46
46
|
src/pyg90alarm/entities/sensor.py
|
|
47
|
-
tests/
|
|
48
|
-
tests/
|
|
47
|
+
tests/conftest.py
|
|
48
|
+
tests/device_mock.py
|
|
49
49
|
tests/test_alarm.py
|
|
50
50
|
tests/test_base_commands.py
|
|
51
51
|
tests/test_callback.py
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright (c) 2023 Ilia Sotnikov
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
# furnished to do so, subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
|
11
|
+
# all copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
# SOFTWARE.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
Performs runtime configuration and exposes custom fixtures for Pytest.
|
|
23
|
+
"""
|
|
24
|
+
import pytest
|
|
25
|
+
from device_mock import DeviceMock
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def pytest_configure(config):
|
|
29
|
+
"""
|
|
30
|
+
Configures `pytest`.
|
|
31
|
+
"""
|
|
32
|
+
config.addinivalue_line("markers", "g90device")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
async def mock_device(request, unused_udp_port_factory):
|
|
37
|
+
"""
|
|
38
|
+
Fixture to instantiate a simulated G90 device allocating random unused
|
|
39
|
+
ports for network exchanges.
|
|
40
|
+
|
|
41
|
+
The fixture should be customized with `g90device` mark containing
|
|
42
|
+
`sent_data` and `notification_data` lists of bytes to simulate the messages
|
|
43
|
+
the device sends back to client and notification messages sent to client,
|
|
44
|
+
respectively.
|
|
45
|
+
"""
|
|
46
|
+
marker = getattr(
|
|
47
|
+
request.node
|
|
48
|
+
.get_closest_marker('g90device'),
|
|
49
|
+
'kwargs', {}
|
|
50
|
+
)
|
|
51
|
+
data = marker.get('sent_data', [])
|
|
52
|
+
notification_data = marker.get('notification_data', [])
|
|
53
|
+
|
|
54
|
+
# Allocate unused ports to listen for client requests on, and to send
|
|
55
|
+
# notification messages to, respectively
|
|
56
|
+
|
|
57
|
+
# Note the `unised_udp_port_factory` comes from `pytest-asyncio` package
|
|
58
|
+
device_port = unused_udp_port_factory()
|
|
59
|
+
notification_port = unused_udp_port_factory()
|
|
60
|
+
device = DeviceMock(
|
|
61
|
+
data, notification_data,
|
|
62
|
+
device_port=device_port, notification_port=notification_port
|
|
63
|
+
)
|
|
64
|
+
await device.start()
|
|
65
|
+
yield device
|
|
66
|
+
device.stop()
|