plugwise 0.27.5__tar.gz → 0.27.7__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.
Files changed (34) hide show
  1. {plugwise-0.27.5 → plugwise-0.27.7}/PKG-INFO +2 -1
  2. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/connections/socket.py +9 -11
  3. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/controller.py +152 -140
  4. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/helper.py +3 -4
  5. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/circle.py +52 -15
  6. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/sed.py +2 -1
  7. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise.egg-info/PKG-INFO +2 -1
  8. {plugwise-0.27.5 → plugwise-0.27.7}/pyproject.toml +6 -6
  9. {plugwise-0.27.5 → plugwise-0.27.7}/LICENSE +0 -0
  10. {plugwise-0.27.5 → plugwise-0.27.7}/README.md +0 -0
  11. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/__init__.py +0 -0
  12. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/connections/__init__.py +0 -0
  13. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/connections/serial.py +0 -0
  14. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/constants.py +0 -0
  15. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/exceptions.py +0 -0
  16. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/messages/__init__.py +0 -0
  17. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/messages/requests.py +0 -0
  18. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/messages/responses.py +0 -0
  19. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/__init__.py +0 -0
  20. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/circle_plus.py +0 -0
  21. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/scan.py +0 -0
  22. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/sense.py +0 -0
  23. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/stealth.py +0 -0
  24. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/nodes/switch.py +0 -0
  25. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/parser.py +0 -0
  26. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/smile.py +0 -0
  27. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/stick.py +0 -0
  28. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise/util.py +0 -0
  29. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise.egg-info/SOURCES.txt +0 -0
  30. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise.egg-info/dependency_links.txt +0 -0
  31. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise.egg-info/requires.txt +0 -0
  32. {plugwise-0.27.5 → plugwise-0.27.7}/plugwise.egg-info/top_level.txt +0 -0
  33. {plugwise-0.27.5 → plugwise-0.27.7}/setup.cfg +0 -0
  34. {plugwise-0.27.5 → plugwise-0.27.7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 0.27.5
3
+ Version: 0.27.7
4
4
  Summary: Plugwise Smile (Adam/Anna/P1), Stretch and USB (Stick) module for Python 3.
5
5
  Home-page: https://github.com/plugwise/python-plugwise
6
6
  Author: Plugwise device owners
@@ -37,6 +37,7 @@ Classifier: License :: OSI Approved :: MIT License
37
37
  Classifier: Operating System :: OS Independent
38
38
  Classifier: Programming Language :: Python :: 3.9
39
39
  Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
40
41
  Classifier: Topic :: Home Automation
41
42
  Requires-Python: >=3.9.0
42
43
  Description-Content-Type: text/markdown
@@ -39,15 +39,14 @@ class SocketConnection(StickConnection):
39
39
  err,
40
40
  )
41
41
  raise PortError(err)
42
- else:
43
- self._reader_start("socket_reader_thread")
44
- self._writer_start("socket_writer_thread")
45
- self._is_connected = True
46
- _LOGGER.debug(
47
- "Successfully connected to host '%s' at port %s",
48
- self._socket_host,
49
- str(self._socket_port),
50
- )
42
+ self._reader_start("socket_reader_thread")
43
+ self._writer_start("socket_writer_thread")
44
+ self._is_connected = True
45
+ _LOGGER.debug(
46
+ "Successfully connected to host '%s' at port %s",
47
+ self._socket_host,
48
+ str(self._socket_port),
49
+ )
51
50
 
52
51
  def _close_connection(self):
53
52
  """Close the socket."""
@@ -76,8 +75,7 @@ class SocketConnection(StickConnection):
76
75
  )
77
76
  self._is_connected = False
78
77
  raise PortError(err)
79
- else:
80
- return socket_data
78
+ return socket_data
81
79
  return None
82
80
 
83
81
  def _write_data(self, data):
@@ -49,6 +49,7 @@ class StickMessageController:
49
49
  self.connection = None
50
50
  self.discovery_finished = False
51
51
  self.expected_responses = {}
52
+ self.lock_expected_responses = threading.Lock()
52
53
  self.init_callback = None
53
54
  self.last_seq_id = None
54
55
  self.message_processor = message_processor
@@ -151,66 +152,67 @@ class StickMessageController:
151
152
  def resend(self, seq_id):
152
153
  """Resend message."""
153
154
  _mac = "<unknown>"
154
- if not self.expected_responses.get(seq_id):
155
- _LOGGER.warning(
156
- "Cannot resend unknown request %s",
157
- str(seq_id),
158
- )
159
- else:
160
- if self.expected_responses[seq_id][0].mac:
161
- _mac = self.expected_responses[seq_id][0].mac.decode(UTF8_DECODE)
162
- _request = self.expected_responses[seq_id][0].__class__.__name__
155
+ with self.lock_expected_responses:
156
+ if not self.expected_responses.get(seq_id):
157
+ _LOGGER.warning(
158
+ "Cannot resend unknown request %s",
159
+ str(seq_id),
160
+ )
161
+ else:
162
+ if self.expected_responses[seq_id][0].mac:
163
+ _mac = self.expected_responses[seq_id][0].mac.decode(UTF8_DECODE)
164
+ _request = self.expected_responses[seq_id][0].__class__.__name__
163
165
 
164
- if self.expected_responses[seq_id][2] == -1:
165
- _LOGGER.debug("Drop single %s to %s ", _request, _mac)
166
- elif self.expected_responses[seq_id][2] <= MESSAGE_RETRY:
167
- if (
168
- isinstance(self.expected_responses[seq_id][0], NodeInfoRequest)
169
- and not self.discovery_finished
170
- ):
171
- # Time out for node which is not discovered yet
172
- # to speedup the initial discover phase skip retries and mark node as not discovered.
173
- _LOGGER.debug(
174
- "Skip retry %s to %s to speedup discover process",
175
- _request,
176
- _mac,
177
- )
178
- if self.expected_responses[seq_id][1]:
179
- self.expected_responses[seq_id][1]()
166
+ if self.expected_responses[seq_id][2] == -1:
167
+ _LOGGER.debug("Drop single %s to %s ", _request, _mac)
168
+ elif self.expected_responses[seq_id][2] <= MESSAGE_RETRY:
169
+ if (
170
+ isinstance(self.expected_responses[seq_id][0], NodeInfoRequest)
171
+ and not self.discovery_finished
172
+ ):
173
+ # Time out for node which is not discovered yet
174
+ # to speedup the initial discover phase skip retries and mark node as not discovered.
175
+ _LOGGER.debug(
176
+ "Skip retry %s to %s to speedup discover process",
177
+ _request,
178
+ _mac,
179
+ )
180
+ if self.expected_responses[seq_id][1]:
181
+ self.expected_responses[seq_id][1]()
182
+ else:
183
+ _LOGGER.info(
184
+ "Resend %s for %s, retry %s of %s",
185
+ _request,
186
+ _mac,
187
+ str(self.expected_responses[seq_id][2] + 1),
188
+ str(MESSAGE_RETRY + 1),
189
+ )
190
+ self.send(
191
+ self.expected_responses[seq_id][0],
192
+ self.expected_responses[seq_id][1],
193
+ self.expected_responses[seq_id][2] + 1,
194
+ )
180
195
  else:
181
- _LOGGER.info(
182
- "Resend %s for %s, retry %s of %s",
196
+ _LOGGER.warning(
197
+ "Drop %s to %s because max retries %s reached",
183
198
  _request,
184
199
  _mac,
185
- str(self.expected_responses[seq_id][2] + 1),
186
200
  str(MESSAGE_RETRY + 1),
187
201
  )
188
- self.send(
189
- self.expected_responses[seq_id][0],
190
- self.expected_responses[seq_id][1],
191
- self.expected_responses[seq_id][2] + 1,
192
- )
193
- else:
194
- _LOGGER.warning(
195
- "Drop %s to %s because max retries %s reached",
196
- _request,
197
- _mac,
198
- str(MESSAGE_RETRY + 1),
199
- )
200
- # Report node as unavailable for missing NodePingRequest
201
- if isinstance(self.expected_responses[seq_id][0], NodePingRequest):
202
- self.node_state(_mac, False)
203
- else:
204
- _LOGGER.debug(
205
- "Do a single ping request to %s to validate if node is reachable",
206
- _mac,
207
- )
208
- self.send(
209
- NodePingRequest(self.expected_responses[seq_id][0].mac),
210
- None,
211
- MESSAGE_RETRY + 1,
212
- )
213
- del self.expected_responses[seq_id]
202
+ # Report node as unavailable for missing NodePingRequest
203
+ if isinstance(self.expected_responses[seq_id][0], NodePingRequest):
204
+ self.node_state(_mac, False)
205
+ else:
206
+ _LOGGER.debug(
207
+ "Do a single ping request to %s to validate if node is reachable",
208
+ _mac,
209
+ )
210
+ self.send(
211
+ NodePingRequest(self.expected_responses[seq_id][0].mac),
212
+ None,
213
+ MESSAGE_RETRY + 1,
214
+ )
215
+ del self.expected_responses[seq_id]
214
216
 
215
217
  def _send_message_loop(self):
216
218
  """Daemon to send messages waiting in queue."""
@@ -225,25 +227,26 @@ class StickMessageController:
225
227
  # Calc next seq_id based last received ack message
226
228
  # if previous seq_id is unknown use fake b"0000"
227
229
  seq_id = inc_seq_id(self.last_seq_id)
228
- self.expected_responses[seq_id] = request_set
229
- if self.expected_responses[seq_id][2] == 0:
230
- _LOGGER.info(
231
- "Send %s to %s using seq_id %s",
232
- self.expected_responses[seq_id][0].__class__.__name__,
233
- self.expected_responses[seq_id][0].mac,
234
- str(seq_id),
235
- )
236
- else:
237
- _LOGGER.info(
238
- "Resend %s to %s using seq_id %s, retry %s",
239
- self.expected_responses[seq_id][0].__class__.__name__,
240
- self.expected_responses[seq_id][0].mac,
241
- str(seq_id),
242
- str(self.expected_responses[seq_id][2]),
243
- )
244
- self.expected_responses[seq_id][3] = datetime.now()
245
- # Send request
246
- self.connection.send(self.expected_responses[seq_id][0])
230
+ with self.lock_expected_responses:
231
+ self.expected_responses[seq_id] = request_set
232
+ if self.expected_responses[seq_id][2] == 0:
233
+ _LOGGER.info(
234
+ "Send %s to %s using seq_id %s",
235
+ self.expected_responses[seq_id][0].__class__.__name__,
236
+ self.expected_responses[seq_id][0].mac,
237
+ str(seq_id),
238
+ )
239
+ else:
240
+ _LOGGER.info(
241
+ "Resend %s to %s using seq_id %s, retry %s",
242
+ self.expected_responses[seq_id][0].__class__.__name__,
243
+ self.expected_responses[seq_id][0].mac,
244
+ str(seq_id),
245
+ str(self.expected_responses[seq_id][2]),
246
+ )
247
+ self.expected_responses[seq_id][3] = datetime.now()
248
+ # Send request
249
+ self.connection.send(self.expected_responses[seq_id][0])
247
250
  time.sleep(SLEEP_TIME)
248
251
  timeout_counter = 0
249
252
  # Wait max 1 second for acknowledge response from USB-stick
@@ -286,63 +289,71 @@ class StickMessageController:
286
289
  )
287
290
 
288
291
  def _post_message_action(self, seq_id, ack_response=None, request="unknown"):
289
- """Execute action if request has been successful.."""
290
- if seq_id in self.expected_responses:
291
- if ack_response in (*REQUEST_SUCCESS, None):
292
- if self.expected_responses[seq_id][1]:
293
- _LOGGER.debug(
294
- "Execute action %s of request with seq_id %s",
295
- self.expected_responses[seq_id][1].__name__,
296
- str(seq_id),
297
- )
298
- try:
299
- self.expected_responses[seq_id][1]()
300
- # TODO: narrow exception
301
- except Exception as err: # pylint: disable=broad-except
302
- _LOGGER.error(
303
- "Execution of %s for request with seq_id %s failed: %s",
292
+ """Execute action if request has been successful."""
293
+ resend_request = False
294
+ with self.lock_expected_responses:
295
+ if seq_id in self.expected_responses:
296
+ if ack_response in (*REQUEST_SUCCESS, None):
297
+ if self.expected_responses[seq_id][1]:
298
+ _LOGGER.debug(
299
+ "Execute action %s of request with seq_id %s",
304
300
  self.expected_responses[seq_id][1].__name__,
305
301
  str(seq_id),
306
- err,
307
302
  )
308
- del self.expected_responses[seq_id]
309
- elif ack_response in REQUEST_FAILED:
310
- self.resend(seq_id)
311
- else:
312
- if not self.last_seq_id:
313
- if b"0000" in self.expected_responses:
314
- self.expected_responses[seq_id] = self.expected_responses[b"0000"]
315
- del self.expected_responses[b"0000"]
316
- self.last_seq_id = seq_id
303
+ try:
304
+ self.expected_responses[seq_id][1]()
305
+ # TODO: narrow exception
306
+ except Exception as err: # pylint: disable=broad-except
307
+ _LOGGER.error(
308
+ "Execution of %s for request with seq_id %s failed: %s",
309
+ self.expected_responses[seq_id][1].__name__,
310
+ str(seq_id),
311
+ err,
312
+ )
313
+ del self.expected_responses[seq_id]
314
+ elif ack_response in REQUEST_FAILED:
315
+ resend_request = True
317
316
  else:
318
- _LOGGER.info(
319
- "Drop unexpected %s%s using seq_id %s",
320
- STATUS_RESPONSES.get(ack_response, "") + " ",
321
- request,
322
- str(seq_id),
323
- )
317
+ if not self.last_seq_id:
318
+ if b"0000" in self.expected_responses:
319
+ self.expected_responses[seq_id] = self.expected_responses[
320
+ b"0000"
321
+ ]
322
+ del self.expected_responses[b"0000"]
323
+ self.last_seq_id = seq_id
324
+ else:
325
+ _LOGGER.info(
326
+ "Drop unexpected %s%s using seq_id %s",
327
+ STATUS_RESPONSES.get(ack_response, "") + " ",
328
+ request,
329
+ str(seq_id),
330
+ )
331
+ if resend_request:
332
+ self.resend(seq_id)
324
333
 
325
334
  def _receive_timeout_loop(self):
326
335
  """Daemon to time out open requests without any (n)ack response message."""
327
336
  while self._receive_timeout_thread_state:
328
- for seq_id in list(self.expected_responses.keys()):
329
- if self.expected_responses[seq_id][3] is not None:
330
- if self.expected_responses[seq_id][3] < (
331
- datetime.now() - timedelta(seconds=MESSAGE_TIME_OUT)
332
- ):
333
- _mac = "<unknown>"
334
- if self.expected_responses[seq_id][0].mac:
335
- _mac = self.expected_responses[seq_id][0].mac.decode(
336
- UTF8_DECODE
337
+ resend_list = []
338
+ with self.lock_expected_responses:
339
+ for seq_id in list(self.expected_responses.keys()):
340
+ if self.expected_responses[seq_id][3] is not None:
341
+ if self.expected_responses[seq_id][3] < (
342
+ datetime.now() - timedelta(seconds=MESSAGE_TIME_OUT)
343
+ ):
344
+ _mac = "<unknown>"
345
+ if self.expected_responses[seq_id][0].mac:
346
+ _mac = self.expected_responses[seq_id][0].mac
347
+ _LOGGER.info(
348
+ "No response within %s seconds timeout for %s to %s with sequence ID %s",
349
+ str(MESSAGE_TIME_OUT),
350
+ self.expected_responses[seq_id][0].__class__.__name__,
351
+ _mac,
352
+ str(seq_id),
337
353
  )
338
- _LOGGER.info(
339
- "No response within %s seconds timeout for %s to %s with sequence ID %s",
340
- str(MESSAGE_TIME_OUT),
341
- self.expected_responses[seq_id][0].__class__.__name__,
342
- _mac,
343
- str(seq_id),
344
- )
345
- self.resend(seq_id)
354
+ resend_list.append(seq_id)
355
+ for seq_id in resend_list:
356
+ self.resend(seq_id)
346
357
  receive_timeout_checker = 0
347
358
  while (
348
359
  receive_timeout_checker < MESSAGE_TIME_OUT
@@ -363,25 +374,26 @@ class StickMessageController:
363
374
  str(message.seq_id),
364
375
  )
365
376
  else:
366
- if self.expected_responses.get(message.seq_id):
367
- _LOGGER.warning(
368
- "Received unmanaged (%s) %s in response to %s with seq_id %s",
369
- str(status),
370
- message.__class__.__name__,
371
- str(
372
- self.expected_responses[message.seq_id][
373
- 1
374
- ].__class__.__name__
375
- ),
376
- str(message.seq_id),
377
- )
378
- else:
379
- _LOGGER.warning(
380
- "Received unmanaged (%s) %s for unknown request with seq_id %s",
381
- str(status),
382
- message.__class__.__name__,
383
- str(message.seq_id),
384
- )
377
+ with self.lock_expected_responses:
378
+ if self.expected_responses.get(message.seq_id):
379
+ _LOGGER.warning(
380
+ "Received unmanaged (%s) %s in response to %s with seq_id %s",
381
+ str(status),
382
+ message.__class__.__name__,
383
+ str(
384
+ self.expected_responses[message.seq_id][
385
+ 1
386
+ ].__class__.__name__
387
+ ),
388
+ str(message.seq_id),
389
+ )
390
+ else:
391
+ _LOGGER.warning(
392
+ "Received unmanaged (%s) %s for unknown request with seq_id %s",
393
+ str(status),
394
+ message.__class__.__name__,
395
+ str(message.seq_id),
396
+ )
385
397
  else:
386
398
  _LOGGER.info(
387
399
  "Received %s from %s with sequence id %s",
@@ -225,7 +225,6 @@ class SmileComm:
225
225
  ):
226
226
  """Set the constructor for this class."""
227
227
  if not websession:
228
-
229
228
  aio_timeout = ClientTimeout(total=timeout)
230
229
 
231
230
  async def _create_session() -> ClientSession:
@@ -303,7 +302,9 @@ class SmileComm:
303
302
  data=data,
304
303
  auth=self._auth,
305
304
  )
306
- except ClientError as err: # ClientError is an ancestor class of ServerTimeoutError
305
+ except (
306
+ ClientError
307
+ ) as err: # ClientError is an ancestor class of ServerTimeoutError
307
308
  if retry < 1:
308
309
  LOGGER.warning(
309
310
  "Failed sending %s %s to Plugwise Smile, error: %s",
@@ -1014,7 +1015,6 @@ class SmileHelper:
1014
1015
  if (
1015
1016
  appliance := self._appliances.find(f'./appliance[@id="{d_id}"]')
1016
1017
  ) is not None:
1017
-
1018
1018
  self._appliance_measurements(appliance, data, measurements)
1019
1019
  self._get_lock_state(appliance, data)
1020
1020
 
@@ -1082,7 +1082,6 @@ class SmileHelper:
1082
1082
  appl_class = appliance_details["dev_class"]
1083
1083
  appl_d_loc = appliance_details["location"]
1084
1084
  if loc_id == appl_d_loc and appl_class in thermo_matching:
1085
-
1086
1085
  # Pre-elect new master
1087
1086
  if thermo_matching[appl_class] > self._thermo_locs[loc_id]["master_prio"]:
1088
1087
  # Demote former master
@@ -66,7 +66,9 @@ class PlugwiseCircle(PlugwiseNode):
66
66
  self._energy_consumption_today_reset = datetime.now().replace(
67
67
  hour=0, minute=0, second=0, microsecond=0
68
68
  )
69
+ self._energy_memory = {}
69
70
  self._energy_history_collecting = False
71
+ self._energy_history_collecting_timestamp = datetime.now()
70
72
  self._energy_history = {}
71
73
  self._energy_last_collected_timestamp = datetime(2000, 1, 1)
72
74
  self._energy_last_rollover_timestamp = datetime(2000, 1, 1)
@@ -613,7 +615,16 @@ class PlugwiseCircle(PlugwiseNode):
613
615
  if log_address is None:
614
616
  log_address = self._last_log_address
615
617
  if log_address is not None:
616
- if len(self._energy_history) > 48 or self._energy_history_collecting:
618
+ if self._energy_history_collecting and (
619
+ self._energy_history_collecting_timestamp
620
+ < datetime.now() - timedelta(minutes=15)
621
+ ):
622
+ _LOGGER.debug(
623
+ "Skip request_energy_counters for %s of address %s",
624
+ self.mac,
625
+ str(log_address),
626
+ )
627
+ elif len(self._energy_history) > 48:
617
628
  # Energy history already collected
618
629
  if (
619
630
  log_address == self._last_log_address
@@ -624,31 +635,53 @@ class PlugwiseCircle(PlugwiseNode):
624
635
  self._request_info(self.request_energy_counters)
625
636
  else:
626
637
  # Request new energy counters
627
- self.message_sender(
628
- CircleEnergyCountersRequest(self._mac, log_address),
629
- None,
630
- 0,
631
- PRIORITY_LOW,
632
- )
638
+ if self._energy_memory.get(log_address, 0) < 4:
639
+ self.message_sender(
640
+ CircleEnergyCountersRequest(self._mac, log_address),
641
+ None,
642
+ 0,
643
+ PRIORITY_LOW,
644
+ )
645
+ else:
646
+ _LOGGER.info(
647
+ "Drop known request_energy_counters for %s of address %s",
648
+ self.mac,
649
+ str(log_address),
650
+ )
633
651
  else:
634
652
  # Collect energy counters of today and yesterday
635
653
  # Each request contains will return 4 hours, except last request
636
654
 
637
655
  # TODO: validate range of log_addresses
638
656
  self._energy_history_collecting = True
657
+ self._energy_history_collecting_timestamp = datetime.now()
639
658
  for req_log_address in range(log_address - 13, log_address):
659
+ if self._energy_memory.get(req_log_address, 0) < 4:
660
+ self.message_sender(
661
+ CircleEnergyCountersRequest(self._mac, req_log_address),
662
+ None,
663
+ 0,
664
+ PRIORITY_LOW,
665
+ )
666
+ else:
667
+ _LOGGER.info(
668
+ "Drop known request_energy_counters at collecting for %s of address %s",
669
+ self.mac,
670
+ str(log_address),
671
+ )
672
+ if self._energy_memory.get(log_address, 0) < 4:
640
673
  self.message_sender(
641
- CircleEnergyCountersRequest(self._mac, req_log_address),
642
- None,
674
+ CircleEnergyCountersRequest(self._mac, log_address),
675
+ callback,
643
676
  0,
644
677
  PRIORITY_LOW,
645
678
  )
646
- self.message_sender(
647
- CircleEnergyCountersRequest(self._mac, log_address),
648
- callback,
649
- 0,
650
- PRIORITY_LOW,
651
- )
679
+ else:
680
+ _LOGGER.info(
681
+ "Drop known request_energy_counters at collecting end for %s of address %s",
682
+ self.mac,
683
+ str(log_address),
684
+ )
652
685
 
653
686
  def _response_energy_counters(self, message: CircleEnergyCountersResponse):
654
687
  """
@@ -677,6 +710,10 @@ class PlugwiseCircle(PlugwiseNode):
677
710
  _log_timestamp := getattr(message, "logdate%d" % (_slot,)).value
678
711
  ) is None:
679
712
  break
713
+ # Register collected history memory
714
+ if _slot > self._energy_memory.get(message.logaddr.value, 0):
715
+ self._energy_memory[message.logaddr.value] = _slot
716
+
680
717
  self._energy_history[_log_timestamp] = getattr(
681
718
  message, "pulses%d" % (_slot,)
682
719
  ).value
@@ -81,7 +81,8 @@ class NodeSED(PlugwiseNode):
81
81
  SED_AWAKE_STARTUP,
82
82
  SED_AWAKE_BUTTON,
83
83
  ]:
84
- for request_message, callback in self._sed_requests.items():
84
+ for pending_request in self._sed_requests.values():
85
+ request_message, callback = pending_request
85
86
  _LOGGER.info(
86
87
  "Send queued %s message to SED node %s",
87
88
  request_message.__class__.__name__,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 0.27.5
3
+ Version: 0.27.7
4
4
  Summary: Plugwise Smile (Adam/Anna/P1), Stretch and USB (Stick) module for Python 3.
5
5
  Home-page: https://github.com/plugwise/python-plugwise
6
6
  Author: Plugwise device owners
@@ -37,6 +37,7 @@ Classifier: License :: OSI Approved :: MIT License
37
37
  Classifier: Operating System :: OS Independent
38
38
  Classifier: Programming Language :: Python :: 3.9
39
39
  Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
40
41
  Classifier: Topic :: Home Automation
41
42
  Requires-Python: >=3.9.0
42
43
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plugwise"
7
- version = "0.27.5"
7
+ version = "0.27.7"
8
8
  license = {file = "LICENSE"}
9
9
  description = "Plugwise Smile (Adam/Anna/P1), Stretch and USB (Stick) module for Python 3."
10
10
  readme = "README.md"
@@ -16,6 +16,7 @@ classifiers = [
16
16
  "Operating System :: OS Independent",
17
17
  "Programming Language :: Python :: 3.9",
18
18
  "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
19
20
  "Topic :: Home Automation",
20
21
  ]
21
22
  authors = [
@@ -50,7 +51,7 @@ include-package-data = true
50
51
  include = ["plugwise*"]
51
52
 
52
53
  [tool.black]
53
- target-version = ["py39", "py310"]
54
+ target-version = ["py39", "py310", "py311"]
54
55
  exclude = 'generated'
55
56
 
56
57
  [tool.isort]
@@ -166,9 +167,8 @@ expected-line-ending-format = "LF"
166
167
 
167
168
  [tool.pylint.EXCEPTIONS]
168
169
  overgeneral-exceptions = [
169
- "BaseException",
170
- "Exception",
171
- "HomeAssistantError",
170
+ "builtins.BaseException",
171
+ "builtins.Exception",
172
172
  ]
173
173
 
174
174
  [tool.pytest.ini_options]
@@ -187,7 +187,7 @@ norecursedirs = [
187
187
  ]
188
188
 
189
189
  [tool.mypy]
190
- python_version = "3.10"
190
+ python_version = "3.11"
191
191
  show_error_codes = true
192
192
  follow_imports = "silent"
193
193
  ignore_missing_imports = true
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes