pyg90alarm 1.13.0__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.
@@ -23,8 +23,13 @@ Implements support for notifications/alerts sent by G90 alarm panel.
23
23
  """
24
24
  import json
25
25
  import logging
26
- from collections import namedtuple
26
+ from typing import (
27
+ Optional, Tuple, List, Any
28
+ )
29
+ from dataclasses import dataclass
27
30
  import asyncio
31
+ from asyncio.transports import BaseTransport
32
+ from asyncio.protocols import DatagramProtocol
28
33
  from .callback import G90Callback
29
34
  from .const import (
30
35
  G90MessageTypes,
@@ -40,64 +45,78 @@ from .const import (
40
45
  _LOGGER = logging.getLogger(__name__)
41
46
 
42
47
 
43
- class G90Message(namedtuple('G90Message',
44
- ['code', 'data'])):
48
+ @dataclass
49
+ class G90Message:
45
50
  """
46
51
  Represents the message received from the device.
47
52
 
48
53
  :meta private:
49
54
  """
55
+ code: G90MessageTypes
56
+ data: List[Any]
50
57
 
51
58
 
52
- class G90Notification(namedtuple('G90Notification',
53
- ['kind', 'data'])):
59
+ @dataclass
60
+ class G90Notification:
54
61
  """
55
62
  Represents the notification received from the device.
56
63
 
57
64
  :meta private:
58
65
  """
66
+ kind: G90NotificationTypes
67
+ data: List[Any]
59
68
 
60
69
 
61
- class G90ZoneInfo(namedtuple('G90ZoneInfo',
62
- ['idx', 'name'])):
70
+ @dataclass
71
+ class G90ZoneInfo:
63
72
  """
64
73
  Represents zone details received from the device.
65
74
 
66
75
  :meta private:
67
76
  """
77
+ idx: int
78
+ name: str
68
79
 
69
80
 
70
- class G90ArmDisarmInfo(namedtuple('G90ArmDisarmInfo',
71
- ['state'])):
81
+ @dataclass
82
+ class G90ArmDisarmInfo:
72
83
  """
73
84
  Represents the arm/disarm state received from the device.
74
85
 
75
86
  :meta private:
76
87
  """
88
+ state: int
77
89
 
78
90
 
79
- class G90DeviceAlert(namedtuple('G90DeviceAlert',
80
- ['type', 'event_id', 'source', 'state',
81
- 'zone_name', 'device_id', 'unix_time',
82
- 'resv4', 'other'])):
91
+ @dataclass
92
+ class G90DeviceAlert: # pylint: disable=too-many-instance-attributes
83
93
  """
84
94
  Represents alert received from the device.
85
-
86
- :meta private:
87
95
  """
88
-
89
-
90
- class G90DeviceNotifications:
96
+ type: G90AlertTypes
97
+ event_id: G90AlertStateChangeTypes
98
+ source: G90AlertSources
99
+ state: int
100
+ zone_name: str
101
+ device_id: str
102
+ unix_time: int
103
+ resv4: int
104
+ other: str
105
+
106
+
107
+ class G90DeviceNotifications(DatagramProtocol):
91
108
  """
92
- tbd
109
+ Implements support for notifications/alerts sent by alarm panel.
93
110
  """
94
- def __init__(self, port, host):
111
+ def __init__(self, port: int, host: str):
95
112
  # pylint: disable=too-many-arguments
96
- self._notification_transport = None
113
+ self._notification_transport: Optional[BaseTransport] = None
97
114
  self._notifications_host = host
98
115
  self._notifications_port = port
99
116
 
100
- def _handle_notification(self, addr, notification):
117
+ def _handle_notification(
118
+ self, addr: Tuple[str, int], notification: G90Notification
119
+ ) -> None:
101
120
  # Sensor activity notification
102
121
  if notification.kind == G90NotificationTypes.SENSOR_ACTIVITY:
103
122
  g90_zone_info = G90ZoneInfo(*notification.data)
@@ -123,7 +142,9 @@ class G90DeviceNotifications:
123
142
  ' kind %s, data %s',
124
143
  addr[0], addr[1], notification.kind, notification.data)
125
144
 
126
- def _handle_alert(self, addr, alert):
145
+ def _handle_alert(
146
+ self, addr: Tuple[str, int], alert: G90DeviceAlert
147
+ ) -> None:
127
148
  if alert.type == G90AlertTypes.DOOR_OPEN_CLOSE:
128
149
  if alert.state in (
129
150
  G90AlertStates.DOOR_OPEN, G90AlertStates.DOOR_CLOSE
@@ -163,7 +184,7 @@ class G90DeviceNotifications:
163
184
  G90AlertStateChangeTypes.DISARM: G90ArmDisarmTypes.DISARM
164
185
  }
165
186
 
166
- state = alarm_arm_disarm_state_map.get(alert.event_id, None)
187
+ state = alarm_arm_disarm_state_map.get(alert.event_id)
167
188
  if state:
168
189
  # We received the device state change related to arm/disarm,
169
190
  # invoke the corresponding callback
@@ -185,17 +206,20 @@ class G90DeviceNotifications:
185
206
 
186
207
  # Implementation of datagram protocol,
187
208
  # https://docs.python.org/3/library/asyncio-protocol.html#datagram-protocols
188
- def connection_made(self, transport):
209
+ def connection_made(self, transport: BaseTransport) -> None:
189
210
  """
190
211
  Invoked when connection from the device is made.
191
212
  """
192
213
 
193
- def connection_lost(self, exc):
214
+ def connection_lost(self, exc: Optional[Exception]) -> None:
194
215
  """
195
216
  Same but when the connection is lost.
196
217
  """
197
218
 
198
- def datagram_received(self, data, addr): # pylint:disable=R0911
219
+ def datagram_received( # pylint:disable=R0911
220
+ self, data: bytes, addr: Tuple[str, int]
221
+ ) -> None:
222
+
199
223
  """
200
224
  Invoked from datagram is received from the device.
201
225
  """
@@ -221,54 +245,56 @@ class G90DeviceNotifications:
221
245
  # Device notifications
222
246
  if g90_message.code == G90MessageTypes.NOTIFICATION:
223
247
  try:
224
- data = G90Notification(*g90_message.data)
248
+ notification_data = G90Notification(*g90_message.data)
225
249
  except TypeError as exc:
226
250
  _LOGGER.error('Bad notification received from %s:%s: %s',
227
251
  addr[0], addr[1], exc)
228
252
  return
229
- self._handle_notification(addr, data)
253
+ self._handle_notification(addr, notification_data)
230
254
  return
231
255
 
232
256
  # Device alerts
233
257
  if g90_message.code == G90MessageTypes.ALERT:
234
258
  try:
235
- data = G90DeviceAlert(*g90_message.data)
259
+ alert_data = G90DeviceAlert(*g90_message.data)
236
260
  except TypeError as exc:
237
261
  _LOGGER.error('Bad alert received from %s:%s: %s',
238
262
  addr[0], addr[1], exc)
239
263
  return
240
- self._handle_alert(addr, data)
264
+ self._handle_alert(addr, alert_data)
241
265
  return
242
266
 
243
267
  _LOGGER.warning('Unknown message received from %s:%s: %s',
244
268
  addr[0], addr[1], message)
245
269
 
246
- async def on_armdisarm(self, state):
270
+ async def on_armdisarm(self, state: G90ArmDisarmTypes) -> None:
247
271
  """
248
272
  Invoked when device is armed or disarmed.
249
273
  """
250
274
 
251
- async def on_sensor_activity(self, idx, name):
275
+ async def on_sensor_activity(self, idx: int, name: str) -> None:
252
276
  """
253
277
  Invoked on sensor activity.
254
278
  """
255
279
 
256
- async def on_door_open_close(self, event_id, zone_name, is_open):
280
+ async def on_door_open_close(
281
+ self, event_id: int, zone_name: str, is_open: bool
282
+ ) -> None:
257
283
  """
258
284
  Invoked when door sensor reports it opened or closed.
259
285
  """
260
286
 
261
- async def on_low_battery(self, event_id, zone_name):
287
+ async def on_low_battery(self, event_id: int, zone_name: str) -> None:
262
288
  """
263
289
  Invoked when a sensor reports it is low on battery.
264
290
  """
265
291
 
266
- async def on_alarm(self, event_id, zone_name):
292
+ async def on_alarm(self, event_id: int, zone_name: str) -> None:
267
293
  """
268
294
  Invoked when device triggers the alarm.
269
295
  """
270
296
 
271
- async def listen(self):
297
+ async def listen(self) -> None:
272
298
  """
273
299
  Listens for notifications/alers from the device.
274
300
  """
@@ -288,15 +314,13 @@ class G90DeviceNotifications:
288
314
  ))
289
315
 
290
316
  @property
291
- def listener_started(self):
317
+ def listener_started(self) -> bool:
292
318
  """
293
319
  Indicates if the listener of the device notifications has been started.
294
-
295
- :rtype: bool
296
320
  """
297
321
  return self._notification_transport is not None
298
322
 
299
- def close(self):
323
+ def close(self) -> None:
300
324
  """
301
325
  Closes the listener.
302
326
  """
pyg90alarm/discovery.py CHANGED
@@ -21,8 +21,10 @@
21
21
  """
22
22
  Discovers G90 alarm panels.
23
23
  """
24
-
24
+ from __future__ import annotations
25
25
  import asyncio
26
+ from typing import Any, List, Tuple
27
+ from dataclasses import dataclass
26
28
  import logging
27
29
 
28
30
  from .base_cmd import G90BaseCommand
@@ -32,45 +34,52 @@ from .const import G90Commands
32
34
  _LOGGER = logging.getLogger(__name__)
33
35
 
34
36
 
37
+ @dataclass
38
+ class G90DiscoveredDevice(G90HostInfo):
39
+ """
40
+ Represents discovered alarm panel.
41
+ """
42
+ host: str
43
+ port: int
44
+ guid: str
45
+
46
+
35
47
  class G90Discovery(G90BaseCommand):
36
48
  """
37
- tbd
49
+ Discovers alarm panels.
38
50
  """
39
51
  # pylint: disable=too-few-public-methods
40
- def __init__(self, timeout=10, **kwargs):
41
- """
42
- tbd
43
- """
52
+ def __init__(self, timeout: float = 10, **kwargs: Any):
44
53
  # pylint: disable=too-many-arguments
45
54
  super().__init__(code=G90Commands.GETHOSTINFO, timeout=timeout,
46
55
  **kwargs)
47
- self._discovered_devices = []
56
+ self._discovered_devices: List[G90DiscoveredDevice] = []
48
57
 
49
58
  # Implementation of datagram protocol,
50
59
  # https://docs.python.org/3/library/asyncio-protocol.html#datagram-protocols
51
- def datagram_received(self, data, addr):
60
+ def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None:
52
61
  """
53
- tbd
62
+ Invoked when some data is received.
54
63
  """
55
64
  try:
56
65
  ret = self.from_wire(data)
57
66
  host_info = G90HostInfo(*ret)
58
67
  _LOGGER.debug('Received from %s:%s: %s', addr[0], addr[1], ret)
59
- res = {
60
- 'guid': host_info.host_guid,
61
- 'host': addr[0],
62
- 'port': addr[1]
63
- }
64
- res.update(host_info._asdict())
68
+ res = G90DiscoveredDevice(
69
+ host=addr[0],
70
+ port=addr[1],
71
+ guid=host_info.host_guid,
72
+ **host_info._asdict()
73
+ )
65
74
  _LOGGER.debug('Discovered device: %s', res)
66
75
  self.add_device(res)
67
76
 
68
77
  except Exception as exc: # pylint: disable=broad-except
69
78
  _LOGGER.warning('Got exception, ignoring: %s', exc)
70
79
 
71
- async def process(self):
80
+ async def process(self) -> G90Discovery:
72
81
  """
73
- tbd
82
+ Initiates device discovery.
74
83
  """
75
84
  _LOGGER.debug('Attempting device discovery...')
76
85
  transport, _ = await self._create_connection()
@@ -78,17 +87,17 @@ class G90Discovery(G90BaseCommand):
78
87
  await asyncio.sleep(self._timeout)
79
88
  transport.close()
80
89
  _LOGGER.debug('Discovered %s devices', len(self.devices))
81
- return self.devices
90
+ return self
82
91
 
83
92
  @property
84
- def devices(self):
93
+ def devices(self) -> List[G90DiscoveredDevice]:
85
94
  """
86
- tbd
95
+ The list of discovered devices.
87
96
  """
88
97
  return self._discovered_devices
89
98
 
90
- def add_device(self, value):
99
+ def add_device(self, value: G90DiscoveredDevice) -> None:
91
100
  """
92
- tbd
101
+ Adds discovered device to the list.
93
102
  """
94
103
  self._discovered_devices.append(value)
@@ -21,7 +21,7 @@
21
21
  """
22
22
  Provides interface to devices (switches) of G90 alarm panel.
23
23
  """
24
-
24
+ from __future__ import annotations
25
25
  import logging
26
26
  from .sensor import G90Sensor
27
27
  from ..const import G90Commands
@@ -35,14 +35,14 @@ class G90Device(G90Sensor):
35
35
  Interacts with device (relay) on G90 alarm panel.
36
36
  """
37
37
 
38
- async def turn_on(self):
38
+ async def turn_on(self) -> None:
39
39
  """
40
40
  Turns on the device (relay)
41
41
  """
42
42
  await self.parent.command(G90Commands.CONTROLDEVICE,
43
43
  [self.index, 0, self.subindex])
44
44
 
45
- async def turn_off(self):
45
+ async def turn_off(self) -> None:
46
46
  """
47
47
  Turns off the device (relay)
48
48
  """
@@ -50,12 +50,11 @@ class G90Device(G90Sensor):
50
50
  [self.index, 1, self.subindex])
51
51
 
52
52
  @property
53
- def supports_enable_disable(self):
53
+ def supports_enable_disable(self) -> bool:
54
54
  """
55
55
  Indicates if disabling/enabling the device (relay) is supported.
56
56
 
57
57
  :return: Support for enabling/disabling the device
58
- :rtype: bool
59
58
  """
60
59
  # No support for manipulating of disable/enabled for the device, since
61
60
  # single protocol entity read from the G90 alarm panel results in
@@ -65,11 +64,11 @@ class G90Device(G90Sensor):
65
64
  # mostly.
66
65
  return False
67
66
 
68
- async def set_enabled(self, value):
67
+ async def set_enabled(self, value: bool) -> None:
69
68
  """
70
69
  Changes the disabled/enabled state of the device (relay).
71
70
 
72
- :param bool value: Whether to enable or disable the device
71
+ :param value: Whether to enable or disable the device
73
72
  """
74
73
  _LOGGER.warning(
75
74
  'Manipulating with enable/disable for device is unsupported'