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/host_info.py
CHANGED
|
@@ -21,26 +21,11 @@
|
|
|
21
21
|
"""
|
|
22
22
|
Protocol entity for G90 alarm panel information.
|
|
23
23
|
"""
|
|
24
|
-
|
|
25
|
-
from
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
from typing import Any, Dict
|
|
26
|
+
from dataclasses import dataclass, asdict
|
|
26
27
|
from enum import IntEnum
|
|
27
28
|
|
|
28
|
-
INCOMING_FIELDS = [
|
|
29
|
-
'host_guid',
|
|
30
|
-
'product_name',
|
|
31
|
-
'wifi_protocol_version',
|
|
32
|
-
'cloud_protocol_version',
|
|
33
|
-
'mcu_hw_version',
|
|
34
|
-
'wifi_hw_version',
|
|
35
|
-
'gsm_status_data',
|
|
36
|
-
'wifi_status_data',
|
|
37
|
-
'reserved1',
|
|
38
|
-
'reserved2',
|
|
39
|
-
'band_frequency',
|
|
40
|
-
'gsm_signal_level',
|
|
41
|
-
'wifi_signal_level'
|
|
42
|
-
]
|
|
43
|
-
|
|
44
29
|
|
|
45
30
|
class G90HostInfoGsmStatus(IntEnum):
|
|
46
31
|
"""
|
|
@@ -62,26 +47,43 @@ class G90HostInfoWifiStatus(IntEnum):
|
|
|
62
47
|
OPERATIONAL = 3
|
|
63
48
|
|
|
64
49
|
|
|
65
|
-
|
|
50
|
+
@dataclass
|
|
51
|
+
class G90HostInfo: # pylint: disable=too-many-instance-attributes
|
|
66
52
|
"""
|
|
67
53
|
Interprets data fields of GETHOSTINFO command.
|
|
68
54
|
"""
|
|
55
|
+
host_guid: str
|
|
56
|
+
product_name: str
|
|
57
|
+
wifi_protocol_version: str
|
|
58
|
+
cloud_protocol_version: str
|
|
59
|
+
mcu_hw_version: str
|
|
60
|
+
wifi_hw_version: str
|
|
61
|
+
gsm_status_data: int
|
|
62
|
+
wifi_status_data: int
|
|
63
|
+
reserved1: int
|
|
64
|
+
reserved2: int
|
|
65
|
+
band_frequency: str
|
|
66
|
+
gsm_signal_level: int
|
|
67
|
+
wifi_signal_level: int
|
|
68
|
+
|
|
69
69
|
@property
|
|
70
|
-
def gsm_status(self):
|
|
70
|
+
def gsm_status(self) -> G90HostInfoGsmStatus:
|
|
71
71
|
"""
|
|
72
72
|
Translates the GSM module status received from the device into
|
|
73
73
|
corresponding enum.
|
|
74
|
-
|
|
75
|
-
:return: :class:`G90HostInfoGsmStatus`
|
|
76
74
|
"""
|
|
77
75
|
return G90HostInfoGsmStatus(self.gsm_status_data)
|
|
78
76
|
|
|
79
77
|
@property
|
|
80
|
-
def wifi_status(self):
|
|
78
|
+
def wifi_status(self) -> G90HostInfoWifiStatus:
|
|
81
79
|
"""
|
|
82
80
|
Translates the Wifi module status received from the device into
|
|
83
81
|
corresponding enum.
|
|
84
|
-
|
|
85
|
-
:return: :class:`G90HostInfoWifiStatus`
|
|
86
82
|
"""
|
|
87
83
|
return G90HostInfoWifiStatus(self.wifi_status_data)
|
|
84
|
+
|
|
85
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
86
|
+
"""
|
|
87
|
+
Returns the host information as dictionary.
|
|
88
|
+
"""
|
|
89
|
+
return asdict(self)
|
pyg90alarm/host_status.py
CHANGED
|
@@ -21,19 +21,32 @@
|
|
|
21
21
|
"""
|
|
22
22
|
Protocol entity for G90 alarm panel status.
|
|
23
23
|
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
from typing import Any, Dict
|
|
26
|
+
from dataclasses import dataclass, asdict
|
|
27
|
+
from .const import G90ArmDisarmTypes
|
|
24
28
|
|
|
25
|
-
from collections import namedtuple
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
'host_phone_number',
|
|
30
|
-
'product_name',
|
|
31
|
-
'mcu_hw_version',
|
|
32
|
-
'wifi_hw_version',
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class G90HostStatus(namedtuple('G90HostStatus', INCOMING_FIELDS)):
|
|
30
|
+
@dataclass
|
|
31
|
+
class G90HostStatus:
|
|
37
32
|
"""
|
|
38
|
-
|
|
33
|
+
Interprets data fields of GETHOSTSTATUS command.
|
|
39
34
|
"""
|
|
35
|
+
host_status_data: int
|
|
36
|
+
host_phone_number: str
|
|
37
|
+
product_name: str
|
|
38
|
+
mcu_hw_version: str
|
|
39
|
+
wifi_hw_version: str
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def host_status(self) -> G90ArmDisarmTypes:
|
|
43
|
+
"""
|
|
44
|
+
Translates host status data to G90ArmDisarmTypes.
|
|
45
|
+
"""
|
|
46
|
+
return G90ArmDisarmTypes(self.host_status_data)
|
|
47
|
+
|
|
48
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
49
|
+
"""
|
|
50
|
+
Returns the host information as dictionary.
|
|
51
|
+
"""
|
|
52
|
+
return asdict(self)
|
pyg90alarm/paginated_cmd.py
CHANGED
|
@@ -21,70 +21,75 @@
|
|
|
21
21
|
"""
|
|
22
22
|
Implements paginated command for G90 alarm panel protocol.
|
|
23
23
|
"""
|
|
24
|
-
|
|
24
|
+
from __future__ import annotations
|
|
25
25
|
import logging
|
|
26
|
-
from
|
|
27
|
-
from
|
|
26
|
+
from typing import Any, cast
|
|
27
|
+
from dataclasses import dataclass
|
|
28
|
+
from .base_cmd import G90BaseCommand, G90BaseCommandData
|
|
28
29
|
from .exceptions import G90Error
|
|
30
|
+
from .const import G90Commands
|
|
29
31
|
|
|
30
32
|
_LOGGER = logging.getLogger(__name__)
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
@dataclass
|
|
36
|
+
class G90PaginationFields:
|
|
35
37
|
"""
|
|
36
|
-
|
|
38
|
+
Represents structure of the pagination fields used by alarm panel.
|
|
37
39
|
|
|
38
40
|
:meta private:
|
|
39
41
|
"""
|
|
42
|
+
total: int
|
|
43
|
+
start: int
|
|
44
|
+
nelems: int
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
class G90PaginatedCommand(G90BaseCommand):
|
|
43
48
|
"""
|
|
44
|
-
|
|
49
|
+
Implements paginated command for alarm panel protocol.
|
|
45
50
|
"""
|
|
46
|
-
def __init__(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
def __init__(
|
|
52
|
+
self, host: str, port: int, code: G90Commands, start: int, end: int,
|
|
53
|
+
**kwargs: Any
|
|
54
|
+
) -> None:
|
|
50
55
|
# pylint: disable=too-many-arguments
|
|
51
56
|
self._start = start
|
|
52
57
|
self._end = end
|
|
53
|
-
self.
|
|
54
|
-
self.
|
|
58
|
+
self._expected_nelems = end - start + 1
|
|
59
|
+
self._nelems = 0
|
|
55
60
|
self._total = 0
|
|
56
61
|
super().__init__(host, port, code, [self._start, self._end],
|
|
57
62
|
**kwargs)
|
|
58
63
|
|
|
59
64
|
@property
|
|
60
|
-
def total(self):
|
|
65
|
+
def total(self) -> int:
|
|
61
66
|
"""
|
|
62
|
-
|
|
67
|
+
Total number of records available.
|
|
63
68
|
"""
|
|
64
69
|
return self._total
|
|
65
70
|
|
|
66
71
|
@property
|
|
67
|
-
def start(self):
|
|
72
|
+
def start(self) -> int:
|
|
68
73
|
"""
|
|
69
|
-
|
|
74
|
+
Index of the first record in the response.
|
|
70
75
|
"""
|
|
71
76
|
return self._start
|
|
72
77
|
|
|
73
78
|
@property
|
|
74
|
-
def count(self):
|
|
79
|
+
def count(self) -> int:
|
|
75
80
|
"""
|
|
76
|
-
|
|
81
|
+
Number of records in the response.
|
|
77
82
|
"""
|
|
78
|
-
return self.
|
|
83
|
+
return self._nelems
|
|
79
84
|
|
|
80
|
-
def _parse(self, data):
|
|
85
|
+
def _parse(self, data: str) -> None:
|
|
81
86
|
"""
|
|
82
|
-
|
|
87
|
+
Parses the response from the alarm panel.
|
|
83
88
|
"""
|
|
84
89
|
super()._parse(data)
|
|
85
|
-
|
|
90
|
+
resp_data: G90BaseCommandData = self._resp.data or []
|
|
86
91
|
try:
|
|
87
|
-
page_data =
|
|
92
|
+
page_data = resp_data.pop(0)
|
|
88
93
|
page_info = G90PaginationFields(*page_data)
|
|
89
94
|
except TypeError as exc:
|
|
90
95
|
raise G90Error(f'Wrong pagination data {page_data} - {str(exc)}'
|
|
@@ -95,25 +100,33 @@ class G90PaginatedCommand(G90BaseCommand):
|
|
|
95
100
|
|
|
96
101
|
self._total = page_info.total
|
|
97
102
|
self._start = page_info.start
|
|
98
|
-
self.
|
|
103
|
+
self._nelems = page_info.nelems
|
|
99
104
|
|
|
100
105
|
errors = []
|
|
101
|
-
if self.
|
|
102
|
-
qualifier =
|
|
106
|
+
if self._nelems != len(resp_data):
|
|
107
|
+
qualifier = (
|
|
108
|
+
"Truncated" if self._nelems > len(resp_data) else "Extra"
|
|
109
|
+
)
|
|
103
110
|
errors.append(
|
|
104
111
|
f'{qualifier} data provided in paginated response -'
|
|
105
|
-
f' expected {self.
|
|
106
|
-
f' received {len(
|
|
112
|
+
f' expected {self._nelems} entities as per response,'
|
|
113
|
+
f' received {len(resp_data)}')
|
|
107
114
|
|
|
108
|
-
if self.
|
|
115
|
+
if self._expected_nelems < len(resp_data):
|
|
109
116
|
errors.append(
|
|
110
117
|
f'Extra data provided in paginated response -'
|
|
111
|
-
f' expected {self.
|
|
112
|
-
f' received {len(
|
|
118
|
+
f' expected {self._expected_nelems} entities as per request,'
|
|
119
|
+
f' received {len(resp_data)}')
|
|
113
120
|
|
|
114
121
|
if errors:
|
|
115
122
|
raise G90Error('. '.join(errors))
|
|
116
123
|
|
|
117
124
|
_LOGGER.debug('Paginated command response: '
|
|
118
125
|
'total records %s, start record %s, record count %s',
|
|
119
|
-
page_info.total, page_info.start, page_info.
|
|
126
|
+
page_info.total, page_info.start, page_info.nelems)
|
|
127
|
+
|
|
128
|
+
async def process(self) -> G90PaginatedCommand:
|
|
129
|
+
"""
|
|
130
|
+
Initiates the command processing.
|
|
131
|
+
"""
|
|
132
|
+
return cast(G90PaginatedCommand, await super().process())
|
pyg90alarm/paginated_result.py
CHANGED
|
@@ -24,21 +24,24 @@ to work with results of paginated commands.
|
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
26
|
import logging
|
|
27
|
-
from
|
|
27
|
+
from typing import Any, Optional, AsyncGenerator, Iterable, cast
|
|
28
|
+
from dataclasses import dataclass
|
|
28
29
|
from .paginated_cmd import G90PaginatedCommand
|
|
29
30
|
from .const import (
|
|
31
|
+
G90Commands,
|
|
30
32
|
CMD_PAGE_SIZE,
|
|
31
33
|
)
|
|
32
34
|
|
|
33
35
|
_LOGGER = logging.getLogger(__name__)
|
|
34
36
|
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
):
|
|
38
|
+
@dataclass
|
|
39
|
+
class G90PaginatedResponse:
|
|
39
40
|
"""
|
|
40
41
|
Response yielded from the :meth:`.G90PaginatedResult.process` method
|
|
41
42
|
"""
|
|
43
|
+
proto_idx: int
|
|
44
|
+
data: str
|
|
42
45
|
|
|
43
46
|
|
|
44
47
|
class G90PaginatedResult:
|
|
@@ -46,7 +49,10 @@ class G90PaginatedResult:
|
|
|
46
49
|
Processes paginated response from G90 corresponding panel commands.
|
|
47
50
|
"""
|
|
48
51
|
# pylint: disable=too-few-public-methods
|
|
49
|
-
def __init__(
|
|
52
|
+
def __init__(
|
|
53
|
+
self, host: str, port: int, code: G90Commands, start: int = 1,
|
|
54
|
+
end: Optional[int] = None, **kwargs: Any
|
|
55
|
+
):
|
|
50
56
|
# pylint: disable=too-many-arguments
|
|
51
57
|
self._host = host
|
|
52
58
|
self._port = port
|
|
@@ -55,7 +61,7 @@ class G90PaginatedResult:
|
|
|
55
61
|
self._end = end
|
|
56
62
|
self._kwargs = kwargs
|
|
57
63
|
|
|
58
|
-
async def process(self):
|
|
64
|
+
async def process(self) -> AsyncGenerator[G90PaginatedResponse, None]:
|
|
59
65
|
"""
|
|
60
66
|
Process paginated response yielding :class:`.G90PaginatedResponse`
|
|
61
67
|
instance for each element.
|
|
@@ -100,7 +106,7 @@ class G90PaginatedResult:
|
|
|
100
106
|
cmd.count, cmd.total, self._end)
|
|
101
107
|
|
|
102
108
|
# Produce the resulting records for the consumer
|
|
103
|
-
for idx, data in enumerate(cmd.result):
|
|
109
|
+
for idx, data in enumerate(cast(Iterable[str], cmd.result)):
|
|
104
110
|
# Protocol uses one-based indexes, `start` implies that so no
|
|
105
111
|
# further additions to resulting value is needed.
|
|
106
112
|
# Note the index provided here is running one across multiple
|
pyg90alarm/py.typed
ADDED
|
File without changes
|
pyg90alarm/targeted_discovery.py
CHANGED
|
@@ -21,58 +21,85 @@
|
|
|
21
21
|
"""
|
|
22
22
|
Discovers G90 alarm panel devices with specific ID.
|
|
23
23
|
"""
|
|
24
|
-
|
|
24
|
+
from __future__ import annotations
|
|
25
25
|
import logging
|
|
26
|
-
from
|
|
27
|
-
from
|
|
26
|
+
from typing import Tuple, Any, Optional, Dict, List
|
|
27
|
+
from dataclasses import dataclass, asdict
|
|
28
|
+
import asyncio
|
|
29
|
+
from asyncio.transports import BaseTransport
|
|
30
|
+
from .base_cmd import G90BaseCommand
|
|
31
|
+
from .const import G90Commands
|
|
28
32
|
from .exceptions import G90Error
|
|
29
33
|
|
|
30
34
|
_LOGGER = logging.getLogger(__name__)
|
|
31
35
|
|
|
32
|
-
INCOMING_FIELDS = [
|
|
33
|
-
'message',
|
|
34
|
-
'product_name',
|
|
35
|
-
'wifi_protocol_version',
|
|
36
|
-
'cloud_protocol_version',
|
|
37
|
-
'mcu_hw_version',
|
|
38
|
-
'fw_version',
|
|
39
|
-
'gsm_status',
|
|
40
|
-
'wifi_status',
|
|
41
|
-
'server_status',
|
|
42
|
-
'reserved1',
|
|
43
|
-
'reserved2',
|
|
44
|
-
'gsm_signal_level',
|
|
45
|
-
'wifi_signal_level'
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class G90TargetedDiscoveryInfo(namedtuple('G90TargetedDiscoveryInfo',
|
|
50
|
-
INCOMING_FIELDS)):
|
|
51
|
-
"""
|
|
52
|
-
tbd
|
|
53
36
|
|
|
54
|
-
|
|
37
|
+
@dataclass
|
|
38
|
+
# pylint: disable=too-many-instance-attributes
|
|
39
|
+
class G90TargetedDiscoveryInfo:
|
|
55
40
|
"""
|
|
41
|
+
Wire representation of the information about discovered device.
|
|
42
|
+
"""
|
|
43
|
+
message: str
|
|
44
|
+
product_name: str
|
|
45
|
+
wifi_protocol_version: str
|
|
46
|
+
cloud_protocol_version: str
|
|
47
|
+
mcu_hw_version: str
|
|
48
|
+
fw_version: str
|
|
49
|
+
gsm_status: str
|
|
50
|
+
wifi_status: str
|
|
51
|
+
server_status: str
|
|
52
|
+
reserved1: str
|
|
53
|
+
reserved2: str
|
|
54
|
+
gsm_signal_level: str
|
|
55
|
+
wifi_signal_level: str
|
|
56
|
+
|
|
57
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
58
|
+
"""
|
|
59
|
+
Returns the information about discovered device as dictionary.
|
|
60
|
+
"""
|
|
61
|
+
return asdict(self)
|
|
56
62
|
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
@dataclass
|
|
65
|
+
class G90DiscoveredDeviceTargeted(G90TargetedDiscoveryInfo):
|
|
59
66
|
"""
|
|
60
|
-
|
|
67
|
+
Discovered device with specific ID.
|
|
61
68
|
"""
|
|
69
|
+
host: str
|
|
70
|
+
port: int
|
|
71
|
+
guid: str
|
|
72
|
+
|
|
62
73
|
|
|
74
|
+
class G90TargetedDiscovery(G90BaseCommand):
|
|
75
|
+
"""
|
|
76
|
+
Discovers alarm panel devices with specific ID.
|
|
77
|
+
"""
|
|
63
78
|
# pylint: disable=too-few-public-methods
|
|
64
|
-
def __init__(self, device_id, **kwargs):
|
|
79
|
+
def __init__(self, device_id: str, **kwargs: Any):
|
|
80
|
+
super().__init__(
|
|
81
|
+
# No actual command will be processed by base class, `NONE` is used
|
|
82
|
+
# for proper typing only
|
|
83
|
+
code=G90Commands.NONE, **kwargs
|
|
84
|
+
)
|
|
85
|
+
self._device_id = device_id
|
|
86
|
+
self._discovered_devices: List[G90DiscoveredDeviceTargeted] = []
|
|
87
|
+
|
|
88
|
+
def connection_made(self, transport: BaseTransport) -> None:
|
|
65
89
|
"""
|
|
66
|
-
|
|
90
|
+
Invoked when connection is established.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def connection_lost(self, exc: Optional[Exception]) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Invoked when connection is lost.
|
|
67
96
|
"""
|
|
68
|
-
super().__init__(**kwargs)
|
|
69
|
-
self._device_id = device_id
|
|
70
97
|
|
|
71
98
|
# Implementation of datagram protocol,
|
|
72
99
|
# https://docs.python.org/3/library/asyncio-protocol.html#datagram-protocols
|
|
73
|
-
def datagram_received(self, data, addr):
|
|
100
|
+
def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None:
|
|
74
101
|
"""
|
|
75
|
-
|
|
102
|
+
Invoked when datagram is received.
|
|
76
103
|
"""
|
|
77
104
|
try:
|
|
78
105
|
_LOGGER.debug('Received from %s:%s: %s', addr[0], addr[1], data)
|
|
@@ -82,17 +109,49 @@ class G90TargetedDiscovery(G90Discovery):
|
|
|
82
109
|
host_info = G90TargetedDiscoveryInfo(*decoded[:-1].split(','))
|
|
83
110
|
if host_info.message != 'IWTAC_PROBE_DEVICE_ACK':
|
|
84
111
|
raise G90Error('Invalid discovery response')
|
|
85
|
-
res =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
112
|
+
res = G90DiscoveredDeviceTargeted(
|
|
113
|
+
host=addr[0],
|
|
114
|
+
port=addr[1],
|
|
115
|
+
guid=self._device_id,
|
|
116
|
+
**host_info._asdict()
|
|
117
|
+
)
|
|
89
118
|
_LOGGER.debug('Discovered device: %s', res)
|
|
90
119
|
self.add_device(res)
|
|
91
120
|
except Exception as exc: # pylint: disable=broad-except
|
|
92
121
|
_LOGGER.warning('Got exception, ignoring: %s', exc)
|
|
93
122
|
|
|
94
|
-
def
|
|
123
|
+
def error_received(self, exc: Exception) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Invoked when error is received.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def to_wire(self) -> bytes:
|
|
95
129
|
"""
|
|
96
|
-
|
|
130
|
+
Converts the command to wire representation.
|
|
97
131
|
"""
|
|
98
132
|
return bytes(f'IWTAC_PROBE_DEVICE,{self._device_id}\0', 'ascii')
|
|
133
|
+
|
|
134
|
+
async def process(self) -> G90TargetedDiscovery:
|
|
135
|
+
"""
|
|
136
|
+
Initiates the device discovery process.
|
|
137
|
+
"""
|
|
138
|
+
_LOGGER.debug('Attempting device discovery...')
|
|
139
|
+
transport, _ = await self._create_connection()
|
|
140
|
+
transport.sendto(self.to_wire())
|
|
141
|
+
await asyncio.sleep(self._timeout)
|
|
142
|
+
transport.close()
|
|
143
|
+
_LOGGER.debug('Discovered %s devices', len(self.devices))
|
|
144
|
+
return self
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def devices(self) -> List[G90DiscoveredDeviceTargeted]:
|
|
148
|
+
"""
|
|
149
|
+
The list of discovered devices.
|
|
150
|
+
"""
|
|
151
|
+
return self._discovered_devices
|
|
152
|
+
|
|
153
|
+
def add_device(self, value: G90DiscoveredDeviceTargeted) -> None:
|
|
154
|
+
"""
|
|
155
|
+
Adds discovered device to the list.
|
|
156
|
+
"""
|
|
157
|
+
self._discovered_devices.append(value)
|
pyg90alarm/user_data_crc.py
CHANGED
|
@@ -22,20 +22,25 @@
|
|
|
22
22
|
Protocol entity for G90 alarm panel that provides checksums of different
|
|
23
23
|
on-device databases.
|
|
24
24
|
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
from typing import Any, Dict
|
|
27
|
+
from dataclasses import dataclass, asdict
|
|
25
28
|
|
|
26
|
-
from collections import namedtuple
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'device_list',
|
|
31
|
-
'history_list',
|
|
32
|
-
'scene_list',
|
|
33
|
-
'ifttt_list',
|
|
34
|
-
'fingerprint_list',
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class G90UserDataCRC(namedtuple('G90UserDataCRC', INCOMING_FIELDS)):
|
|
30
|
+
@dataclass
|
|
31
|
+
class G90UserDataCRC:
|
|
39
32
|
"""
|
|
40
|
-
|
|
33
|
+
Represents structure of GETUSERDATACRC command response.
|
|
41
34
|
"""
|
|
35
|
+
sensor_list: str
|
|
36
|
+
device_list: str
|
|
37
|
+
history_list: str
|
|
38
|
+
scene_list: str
|
|
39
|
+
ifttt_list: str
|
|
40
|
+
fingerprint_list: str
|
|
41
|
+
|
|
42
|
+
def _asdict(self) -> Dict[str, Any]:
|
|
43
|
+
"""
|
|
44
|
+
Returns the host information as dictionary.
|
|
45
|
+
"""
|
|
46
|
+
return asdict(self)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyg90alarm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.0
|
|
4
4
|
Summary: G90 Alarm system protocol
|
|
5
5
|
Home-page: https://github.com/hostcc/pyg90alarm
|
|
6
6
|
Author: Ilia Sotnikov
|
|
@@ -15,12 +15,13 @@ Classifier: Topic :: Home Automation
|
|
|
15
15
|
Classifier: Topic :: System :: Hardware
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.8
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
23
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.8, <4
|
|
24
25
|
Description-Content-Type: text/x-rst
|
|
25
26
|
License-File: LICENSE
|
|
26
27
|
Provides-Extra: dev
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
pyg90alarm/__init__.py,sha256=5AITRm5jZSzuQaL7PS8fZZMZb4-IuGRhSqyAdfTt0Cs,2236
|
|
2
|
+
pyg90alarm/alarm.py,sha256=N2TTK1F1ZVmj_fCxrx1zNvdMO6HsPOz4yIVcoWnyd2I,31777
|
|
3
|
+
pyg90alarm/base_cmd.py,sha256=wu2v_RKpcPHxUW4HBDLWcUFMzPsGooY4o2Rc0LgcanU,9754
|
|
4
|
+
pyg90alarm/callback.py,sha256=3JsD_JChmZD24OyjaCP-PxxuBDBX7myGYhkM4RN7bk4,3742
|
|
5
|
+
pyg90alarm/config.py,sha256=2YtIgdT7clQXmYvkdn_fhIdS05CY8E1Yc90R8_tAmRI,1961
|
|
6
|
+
pyg90alarm/const.py,sha256=4eJyEZpUE5XZkNL1sePKnuPloIvcjKIAJJ4g2e1cXVA,6054
|
|
7
|
+
pyg90alarm/device_notifications.py,sha256=I5K8IsyYTe0XDJT8XiQoC8a2xY1XLjaGx4QFrEsaixg,11135
|
|
8
|
+
pyg90alarm/discovery.py,sha256=fwyBHDCKGej06OwhpbVCHYTRU9WWkeYysAFgv3FiwqI,3575
|
|
9
|
+
pyg90alarm/exceptions.py,sha256=eiOcRe7D18EIPyPFDNU9DdFgbnkwPmkiLl8lGPOhBNw,1475
|
|
10
|
+
pyg90alarm/history.py,sha256=st9RWfrBbn4LLjfz3MguocPSnaTIATzIiBq2hLNeVTY,7380
|
|
11
|
+
pyg90alarm/host_info.py,sha256=4lFIaFEpYd3EvgNrDJmKijTrzX9i29nFISLLlXGnkmE,2759
|
|
12
|
+
pyg90alarm/host_status.py,sha256=4XhuilBzB8XsXkpeWj3PAVpmDPcTnBBOYunO21Flabo,1862
|
|
13
|
+
pyg90alarm/paginated_cmd.py,sha256=vJ8slMS7aNLpkAxnIe25EHstusYy1bYTl1j306ps-MQ,4439
|
|
14
|
+
pyg90alarm/paginated_result.py,sha256=Zs_yB9UW6VlHRBPIzOwHy8ZJ0FqCUPMB-rmfPG2BdnU,5447
|
|
15
|
+
pyg90alarm/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
pyg90alarm/targeted_discovery.py,sha256=zD-oW8u75H39sBanKX_Cjwz3_z_n__TC20doSctmy-g,5336
|
|
17
|
+
pyg90alarm/user_data_crc.py,sha256=JQBOPY3RlOgVtvR55R-rM8OuKjYW-BPXQ0W4pi6CEH0,1689
|
|
18
|
+
pyg90alarm/definitions/__init__.py,sha256=s0NZnkW_gMH718DJbgez28z9WA231CyszUf1O_ojUiI,68
|
|
19
|
+
pyg90alarm/definitions/sensors.py,sha256=rKOu21ZpI44xk6aMh_vBjniFqnsNTc1CKwAvnv4PYLQ,19904
|
|
20
|
+
pyg90alarm/entities/__init__.py,sha256=hHb6AOiC4Tz--rOWiiICMdLaZDs1Tf_xpWk_HeS_gO4,66
|
|
21
|
+
pyg90alarm/entities/device.py,sha256=f_LHvKCAqTEebZ4mrRh3CpPUI7o-OvpvOfyTRCbftJs,2818
|
|
22
|
+
pyg90alarm/entities/sensor.py,sha256=qg08Myz_P4aTd29R37Js0feSfuJ-u2U6F-6FZiS76D0,15124
|
|
23
|
+
pyg90alarm-1.14.0.dist-info/LICENSE,sha256=f884inRbeNv-O-hbwz62Ro_1J8xiHRTnJ2cCx6A0WvU,1070
|
|
24
|
+
pyg90alarm-1.14.0.dist-info/METADATA,sha256=Km8Q2Kl5fdxdypLxpA201_A8kfujIpzu5hiSozidmR4,7663
|
|
25
|
+
pyg90alarm-1.14.0.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
26
|
+
pyg90alarm-1.14.0.dist-info/top_level.txt,sha256=czHiGxYMyTk5QEDTDb0EpPiKqUMRa8zI4zx58Ii409M,11
|
|
27
|
+
pyg90alarm-1.14.0.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
pyg90alarm/__init__.py,sha256=zidYApReScSFZCpC9Tk7pdsBNPMql6XiUtt-O7l3D5M,1381
|
|
2
|
-
pyg90alarm/alarm.py,sha256=aEKmWt_iofBHo2bI59uuCcqBDHeppj2B32_wcBVWBgE,30023
|
|
3
|
-
pyg90alarm/base_cmd.py,sha256=rjpjIzEgtI5mUvmurBasrt9psYKdbIEsivnx8QboivY,8561
|
|
4
|
-
pyg90alarm/callback.py,sha256=zg698TCjjYhjAMk770J9CZp8-dDbX0Zj5wtoC6axq6w,4033
|
|
5
|
-
pyg90alarm/config.py,sha256=FiYjiz_WrDH2OEqHyUJXZDDK7v1fLAUpZcQ3JRMmmX0,1974
|
|
6
|
-
pyg90alarm/const.py,sha256=XP_x5w6quiKQceOJDpExXI86L5KbQLdTed4lbjlNth0,5760
|
|
7
|
-
pyg90alarm/device_notifications.py,sha256=JLdOIIwyoxQdqvIjuLj6_5Rz_W6slYeM8HBPzPIa1ew,10628
|
|
8
|
-
pyg90alarm/discovery.py,sha256=sPk2mRhc0IgpOIlC9kRlKCnlAfdXsT7TyWfHAc1bfqQ,3077
|
|
9
|
-
pyg90alarm/exceptions.py,sha256=eiOcRe7D18EIPyPFDNU9DdFgbnkwPmkiLl8lGPOhBNw,1475
|
|
10
|
-
pyg90alarm/history.py,sha256=Ln3-v8hvagIXTmj_2iURE3oOsVLeQb8OMczUy-SKSRs,7039
|
|
11
|
-
pyg90alarm/host_info.py,sha256=fGGI2ZH6GVD0WhYT72rIELTbiIAmmPiT31eZkyVugwY,2571
|
|
12
|
-
pyg90alarm/host_status.py,sha256=PEPgpkfGNkUzKUgRpfPKldz5qq3_9lqBwX86Ld613vk,1406
|
|
13
|
-
pyg90alarm/paginated_cmd.py,sha256=7pXLAgFQHheByBpwRV-I1yEdZnm8hk6j2OMPZ_Wn-vE,3768
|
|
14
|
-
pyg90alarm/paginated_result.py,sha256=xweFfPLn1a2yYm5h0AxGoDCyDIoy0JkUC_tI80vsrLc,5246
|
|
15
|
-
pyg90alarm/targeted_discovery.py,sha256=DPxNvs8qJfyIOq6KLBYBpqkHPCpHbMW70_gfNyvNAoY,3221
|
|
16
|
-
pyg90alarm/user_data_crc.py,sha256=RsQlbuXC4baD88hX4y0XdysmxEMtQkqkNVX_FhTLSmw,1467
|
|
17
|
-
pyg90alarm/definitions/__init__.py,sha256=s0NZnkW_gMH718DJbgez28z9WA231CyszUf1O_ojUiI,68
|
|
18
|
-
pyg90alarm/definitions/sensors.py,sha256=2Liap0stTT5qNmvsbP_7UscA21IYXQcSAKQLLm7YfHQ,19921
|
|
19
|
-
pyg90alarm/entities/__init__.py,sha256=hHb6AOiC4Tz--rOWiiICMdLaZDs1Tf_xpWk_HeS_gO4,66
|
|
20
|
-
pyg90alarm/entities/device.py,sha256=QbsQyIq2wFLjIH389zyD3d0CyME_rpG_ciD3srAdqXQ,2772
|
|
21
|
-
pyg90alarm/entities/sensor.py,sha256=AkVj_qrK35K5SwSlAHXU9UXdBKVaJzV4TBcoeZUevn4,13942
|
|
22
|
-
pyg90alarm-1.12.1.dist-info/LICENSE,sha256=f884inRbeNv-O-hbwz62Ro_1J8xiHRTnJ2cCx6A0WvU,1070
|
|
23
|
-
pyg90alarm-1.12.1.dist-info/METADATA,sha256=AECT6-eg76TO0qbW2VXZQARBlzpYjtnxOL-BuM-R_3E,7611
|
|
24
|
-
pyg90alarm-1.12.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
|
25
|
-
pyg90alarm-1.12.1.dist-info/top_level.txt,sha256=czHiGxYMyTk5QEDTDb0EpPiKqUMRa8zI4zx58Ii409M,11
|
|
26
|
-
pyg90alarm-1.12.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|