pyg90alarm 1.10.0__py3-none-any.whl → 1.12.1__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.
@@ -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
- # Gas Detector WGD02
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,
@@ -21,7 +21,6 @@
21
21
  """
22
22
  Implements support for notifications/alerts sent by G90 alarm panel.
23
23
  """
24
-
25
24
  import json
26
25
  import logging
27
26
  from collections import namedtuple
@@ -34,15 +33,17 @@ from .const import (
34
33
  G90AlertStateChangeTypes,
35
34
  G90ArmDisarmTypes,
36
35
  G90AlertSources,
36
+ G90AlertStates,
37
37
  )
38
38
 
39
+
39
40
  _LOGGER = logging.getLogger(__name__)
40
41
 
41
42
 
42
43
  class G90Message(namedtuple('G90Message',
43
44
  ['code', 'data'])):
44
45
  """
45
- tbd
46
+ Represents the message received from the device.
46
47
 
47
48
  :meta private:
48
49
  """
@@ -51,7 +52,7 @@ class G90Message(namedtuple('G90Message',
51
52
  class G90Notification(namedtuple('G90Notification',
52
53
  ['kind', 'data'])):
53
54
  """
54
- tbd
55
+ Represents the notification received from the device.
55
56
 
56
57
  :meta private:
57
58
  """
@@ -60,7 +61,7 @@ class G90Notification(namedtuple('G90Notification',
60
61
  class G90ZoneInfo(namedtuple('G90ZoneInfo',
61
62
  ['idx', 'name'])):
62
63
  """
63
- tbd
64
+ Represents zone details received from the device.
64
65
 
65
66
  :meta private:
66
67
  """
@@ -69,7 +70,7 @@ class G90ZoneInfo(namedtuple('G90ZoneInfo',
69
70
  class G90ArmDisarmInfo(namedtuple('G90ArmDisarmInfo',
70
71
  ['state'])):
71
72
  """
72
- tbd
73
+ Represents the arm/disarm state received from the device.
73
74
 
74
75
  :meta private:
75
76
  """
@@ -80,46 +81,31 @@ class G90DeviceAlert(namedtuple('G90DeviceAlert',
80
81
  'zone_name', 'device_id', 'unix_time',
81
82
  'resv4', 'other'])):
82
83
  """
83
- tbd
84
+ Represents alert received from the device.
84
85
 
85
86
  :meta private:
86
87
  """
87
88
 
88
89
 
89
- class G90DeviceNotificationProtocol:
90
+ class G90DeviceNotifications:
90
91
  """
91
92
  tbd
92
-
93
- :meta private:
94
93
  """
95
- def __init__(self, armdisarm_cb=None, sensor_cb=None,
96
- door_open_close_cb=None, alarm_cb=None):
97
- """
98
- tbd
99
- """
100
- self._armdisarm_cb = armdisarm_cb
101
- self._sensor_cb = sensor_cb
102
- self._door_open_close_cb = door_open_close_cb
103
- self._alarm_cb = alarm_cb
104
-
105
- def connection_made(self, transport):
106
- """
107
- tbd
108
- """
109
-
110
- def connection_lost(self, exc):
111
- """
112
- tbd
113
- """
94
+ def __init__(self, port, host):
95
+ # pylint: disable=too-many-arguments
96
+ self._notification_transport = None
97
+ self._notifications_host = host
98
+ self._notifications_port = port
114
99
 
115
100
  def _handle_notification(self, addr, notification):
116
101
  # Sensor activity notification
117
102
  if notification.kind == G90NotificationTypes.SENSOR_ACTIVITY:
118
103
  g90_zone_info = G90ZoneInfo(*notification.data)
119
104
  _LOGGER.debug('Sensor notification: %s', g90_zone_info)
120
- G90Callback.invoke(self._sensor_cb,
121
- g90_zone_info.idx,
122
- g90_zone_info.name)
105
+ G90Callback.invoke(
106
+ self.on_sensor_activity,
107
+ g90_zone_info.idx, g90_zone_info.name
108
+ )
123
109
  return
124
110
 
125
111
  # Arm/disarm notification
@@ -130,8 +116,7 @@ class G90DeviceNotificationProtocol:
130
116
  state = G90ArmDisarmTypes(g90_armdisarm_info.state)
131
117
  _LOGGER.debug('Arm/disarm notification: %s',
132
118
  state)
133
- G90Callback.invoke(self._armdisarm_cb,
134
- state)
119
+ G90Callback.invoke(self.on_armdisarm, state)
135
120
  return
136
121
 
137
122
  _LOGGER.warning('Unknown notification received from %s:%s:'
@@ -140,14 +125,30 @@ class G90DeviceNotificationProtocol:
140
125
 
141
126
  def _handle_alert(self, addr, alert):
142
127
  if alert.type == G90AlertTypes.DOOR_OPEN_CLOSE:
143
- is_open = (
144
- alert.source == G90AlertSources.SENSOR and alert.state == 1
145
- ) or alert.source == G90AlertSources.DOORBELL
146
- _LOGGER.debug('Door open_close alert: %s', alert)
147
- G90Callback.invoke(self._door_open_close_cb,
148
- alert.event_id, alert.zone_name,
149
- is_open)
150
- return
128
+ if alert.state in (
129
+ G90AlertStates.DOOR_OPEN, G90AlertStates.DOOR_CLOSE
130
+ ):
131
+ is_open = (
132
+ alert.source == G90AlertSources.SENSOR
133
+ and alert.state == G90AlertStates.DOOR_OPEN # noqa: W503
134
+ ) or alert.source == G90AlertSources.DOORBELL
135
+ _LOGGER.debug('Door open_close alert: %s', alert)
136
+ G90Callback.invoke(
137
+ self.on_door_open_close,
138
+ alert.event_id, alert.zone_name, is_open
139
+ )
140
+ return
141
+
142
+ if (
143
+ alert.source == G90AlertSources.SENSOR
144
+ and alert.state == G90AlertStates.LOW_BATTERY # noqa: W503
145
+ ):
146
+ _LOGGER.debug('Low battery alert: %s', alert)
147
+ G90Callback.invoke(
148
+ self.on_low_battery,
149
+ alert.event_id, alert.zone_name
150
+ )
151
+ return
151
152
 
152
153
  if alert.type == G90AlertTypes.STATE_CHANGE:
153
154
  # Define the mapping between device state received in the alert, to
@@ -167,21 +168,36 @@ class G90DeviceNotificationProtocol:
167
168
  # We received the device state change related to arm/disarm,
168
169
  # invoke the corresponding callback
169
170
  _LOGGER.debug('Arm/disarm state change: %s', state)
170
- G90Callback.invoke(self._armdisarm_cb, state)
171
+ G90Callback.invoke(self.on_armdisarm, state)
171
172
  return
172
173
 
173
174
  if alert.type == G90AlertTypes.ALARM:
174
175
  _LOGGER.debug('Alarm: %s', alert.zone_name)
175
- G90Callback.invoke(self._alarm_cb, alert.event_id, alert.zone_name)
176
+ G90Callback.invoke(
177
+ self.on_alarm,
178
+ alert.event_id, alert.zone_name
179
+ )
176
180
  return
177
181
 
178
182
  _LOGGER.warning('Unknown alert received from %s:%s:'
179
183
  ' type %s, data %s',
180
184
  addr[0], addr[1], alert.type, alert)
181
185
 
186
+ # Implementation of datagram protocol,
187
+ # https://docs.python.org/3/library/asyncio-protocol.html#datagram-protocols
188
+ def connection_made(self, transport):
189
+ """
190
+ Invoked when connection from the device is made.
191
+ """
192
+
193
+ def connection_lost(self, exc):
194
+ """
195
+ Same but when the connection is lost.
196
+ """
197
+
182
198
  def datagram_received(self, data, addr): # pylint:disable=R0911
183
199
  """
184
- tbd
200
+ Invoked from datagram is received from the device.
185
201
  """
186
202
  s_data = data.decode('utf-8')
187
203
  if not s_data.endswith('\0'):
@@ -227,59 +243,64 @@ class G90DeviceNotificationProtocol:
227
243
  _LOGGER.warning('Unknown message received from %s:%s: %s',
228
244
  addr[0], addr[1], message)
229
245
 
246
+ async def on_armdisarm(self, state):
247
+ """
248
+ Invoked when device is armed or disarmed.
249
+ """
230
250
 
231
- class G90DeviceNotifications:
232
- """
233
- tbd
234
- """
235
- def __init__(self, port=12901, armdisarm_cb=None, sensor_cb=None,
236
- door_open_close_cb=None, alarm_cb=None, sock=None):
237
- # pylint: disable=too-many-arguments
238
- self._notification_transport = None
239
- self._port = port
240
- self._armdisarm_cb = armdisarm_cb
241
- self._sensor_cb = sensor_cb
242
- self._door_open_close_cb = door_open_close_cb
243
- self._alarm_cb = alarm_cb
244
- self._sock = sock
245
-
246
- def proto_factory(self):
251
+ async def on_sensor_activity(self, idx, name):
252
+ """
253
+ Invoked on sensor activity.
254
+ """
255
+
256
+ async def on_door_open_close(self, event_id, zone_name, is_open):
257
+ """
258
+ Invoked when door sensor reports it opened or closed.
259
+ """
260
+
261
+ async def on_low_battery(self, event_id, zone_name):
247
262
  """
248
- tbd
263
+ Invoked when a sensor reports it is low on battery.
264
+ """
265
+
266
+ async def on_alarm(self, event_id, zone_name):
267
+ """
268
+ Invoked when device triggers the alarm.
249
269
  """
250
- return G90DeviceNotificationProtocol(
251
- armdisarm_cb=self._armdisarm_cb,
252
- sensor_cb=self._sensor_cb,
253
- door_open_close_cb=self._door_open_close_cb,
254
- alarm_cb=self._alarm_cb
255
- )
256
270
 
257
271
  async def listen(self):
258
272
  """
259
- tbd
273
+ Listens for notifications/alers from the device.
260
274
  """
261
275
  try:
262
276
  loop = asyncio.get_running_loop()
263
277
  except AttributeError:
264
278
  loop = asyncio.get_event_loop()
265
279
 
266
- if self._sock:
267
- _LOGGER.debug('Using provided socket %s', self._sock)
268
- (self._notification_transport,
269
- _protocol) = await loop.create_datagram_endpoint(
270
- self.proto_factory,
271
- sock=self._sock)
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))
280
+ _LOGGER.debug('Creating UDP endpoint for %s:%s',
281
+ self._notifications_host,
282
+ self._notifications_port)
283
+ (self._notification_transport,
284
+ _protocol) = await loop.create_datagram_endpoint(
285
+ lambda: self,
286
+ local_addr=(
287
+ self._notifications_host, self._notifications_port
288
+ ))
289
+
290
+ @property
291
+ def listener_started(self):
292
+ """
293
+ Indicates if the listener of the device notifications has been started.
294
+
295
+ :rtype: bool
296
+ """
297
+ return self._notification_transport is not None
279
298
 
280
299
  def close(self):
281
300
  """
282
- tbd
301
+ Closes the listener.
283
302
  """
284
303
  if self._notification_transport:
304
+ _LOGGER.debug('No longer listening for device notifications')
285
305
  self._notification_transport.close()
306
+ self._notification_transport = None
pyg90alarm/discovery.py CHANGED
@@ -32,34 +32,28 @@ from .const import G90Commands
32
32
  _LOGGER = logging.getLogger(__name__)
33
33
 
34
34
 
35
- class G90DiscoveryProtocol:
35
+ class G90Discovery(G90BaseCommand):
36
36
  """
37
37
  tbd
38
-
39
- :meta private:
40
38
  """
41
- def __init__(self, parent):
42
- """
43
- tbd
44
- """
45
- self._parent = parent
46
-
47
- def connection_made(self, transport):
48
- """
49
- tbd
50
- """
51
-
52
- def connection_lost(self, exc):
39
+ # pylint: disable=too-few-public-methods
40
+ def __init__(self, timeout=10, **kwargs):
53
41
  """
54
42
  tbd
55
43
  """
44
+ # pylint: disable=too-many-arguments
45
+ super().__init__(code=G90Commands.GETHOSTINFO, timeout=timeout,
46
+ **kwargs)
47
+ self._discovered_devices = []
56
48
 
49
+ # Implementation of datagram protocol,
50
+ # https://docs.python.org/3/library/asyncio-protocol.html#datagram-protocols
57
51
  def datagram_received(self, data, addr):
58
52
  """
59
53
  tbd
60
54
  """
61
55
  try:
62
- ret = self._parent.from_wire(data)
56
+ ret = self.from_wire(data)
63
57
  host_info = G90HostInfo(*ret)
64
58
  _LOGGER.debug('Received from %s:%s: %s', addr[0], addr[1], ret)
65
59
  res = {
@@ -69,31 +63,11 @@ class G90DiscoveryProtocol:
69
63
  }
70
64
  res.update(host_info._asdict())
71
65
  _LOGGER.debug('Discovered device: %s', res)
72
- self._parent.add_device(res)
66
+ self.add_device(res)
73
67
 
74
68
  except Exception as exc: # pylint: disable=broad-except
75
69
  _LOGGER.warning('Got exception, ignoring: %s', exc)
76
70
 
77
- def error_received(self, exc):
78
- """
79
- tbd
80
- """
81
-
82
-
83
- class G90Discovery(G90BaseCommand):
84
- """
85
- tbd
86
- """
87
- # pylint: disable=too-few-public-methods
88
- def __init__(self, timeout=10, **kwargs):
89
- """
90
- tbd
91
- """
92
- # pylint: disable=too-many-arguments
93
- super().__init__(code=G90Commands.GETHOSTINFO, timeout=timeout,
94
- **kwargs)
95
- self._discovered_devices = []
96
-
97
71
  async def process(self):
98
72
  """
99
73
  tbd
@@ -118,9 +92,3 @@ class G90Discovery(G90BaseCommand):
118
92
  tbd
119
93
  """
120
94
  self._discovered_devices.append(value)
121
-
122
- def _proto_factory(self):
123
- """
124
- tbd
125
- """
126
- return G90DiscoveryProtocol(self)
@@ -172,6 +172,7 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
172
172
  self._subindex = subindex
173
173
  self._occupancy = False
174
174
  self._state_callback = None
175
+ self._low_battery_callback = None
175
176
  self._proto_idx = proto_idx
176
177
  self._extra_data = None
177
178
 
@@ -217,6 +218,25 @@ class G90Sensor: # pylint:disable=too-many-instance-attributes
217
218
  """
218
219
  self._state_callback = value
219
220
 
221
+ @property
222
+ def low_battery_callback(self):
223
+ """
224
+ Returns callback the sensor might have set for low battery condition.
225
+
226
+ :return: Sensor's low battery callback
227
+ :rtype: object
228
+ """
229
+ return self._low_battery_callback
230
+
231
+ @low_battery_callback.setter
232
+ def low_battery_callback(self, value):
233
+ """
234
+ Sets callback for the low battery condition reported by the sensor.
235
+
236
+ :param object value: Sensor's low battery callback
237
+ """
238
+ self._low_battery_callback = value
239
+
220
240
  @property
221
241
  def occupancy(self):
222
242
  """