Skip to content

Commit 70d4992

Browse files
committed
Rework energy_log_update() by combining previously used and recent code
1 parent ae4d939 commit 70d4992

File tree

1 file changed

+47
-83
lines changed

1 file changed

+47
-83
lines changed

plugwise_usb/nodes/circle.py

Lines changed: 47 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,10 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
401401
self._log_no_energy_stats_update()
402402
return None
403403

404-
# Always request last energy log records at initial startup
404+
# Always request the most recent energy log records at initial startup, check if the current
405+
# address is acutally reported by the node even when all slots at that address are empty.
405406
if not self._last_energy_log_requested:
406-
self._last_energy_log_requested = await self.energy_log_update(
407+
self._last_energy_log_requested, _ = await self.energy_log_update(
407408
self._current_log_address, save_cache=False
408409
)
409410

@@ -416,8 +417,8 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
416417
)
417418
return None
418419

419-
# Try collecting energy-stats for _current_log_address
420-
result = await self.energy_log_update(
420+
# Try collecting energy-stats from _current_log_address
421+
result, _ = await self.energy_log_update(
421422
self._current_log_address, save_cache=False
422423
)
423424
if not result:
@@ -428,20 +429,17 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
428429
)
429430
return None
430431

431-
if self._current_log_address is not None:
432-
# Retry with previous log address as Circle node pointer to self._current_log_address
433-
# could be rolled over while the last log is at previous address/slot
434-
prev_log_address, _ = calc_log_address(self._current_log_address, 1, -4)
435-
result = await self.energy_log_update(
436-
prev_log_address, save_cache=False
432+
# Retry with previous log address as Circle node pointer to self._current_log_address
433+
# could be rolled over while the last log is at previous address
434+
prev_log_address, _ = calc_log_address(self._current_log_address, 1, -4)
435+
result, _ = await self.energy_log_update(prev_log_address, save_cache=False)
436+
if not result:
437+
_LOGGER.debug(
438+
"async_energy_update | %s | Log rollover | energy_log_update from address %s failed",
439+
self._mac_in_str,
440+
prev_log_address,
437441
)
438-
if not result:
439-
_LOGGER.debug(
440-
"async_energy_update | %s | Log rollover | energy_log_update from address %s failed",
441-
self._mac_in_str,
442-
prev_log_address,
443-
)
444-
return None
442+
return None
445443

446444
if self._cache_enabled:
447445
await self.save_cache()
@@ -458,7 +456,7 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
458456
return self._energy_counters.energy_statistics
459457

460458
if len(missing_addresses) == 1:
461-
result = await self.energy_log_update(
459+
result, _ = await self.energy_log_update(
462460
missing_addresses[0], save_cache=True
463461
)
464462
if result:
@@ -521,8 +519,11 @@ async def _get_initial_energy_logs(self) -> None:
521519
)
522520
log_address = self._current_log_address
523521
while total_addresses > 0:
524-
result = await self.energy_log_update(log_address, save_cache=False)
525-
if not result:
522+
result, slots_empty = await self.energy_log_update(
523+
log_address, save_cache=False
524+
)
525+
if result and not slots_empty:
526+
# (address with outdated data in slots is stored as with None data!)
526527
# Stop initial log collection when an address contains no (None) or outdated data
527528
# Outdated data can indicate a EnergyLog address rollover: from address 6014 to 0
528529
_LOGGER.debug(
@@ -575,14 +576,17 @@ async def get_missing_energy_logs(self) -> None:
575576

576577
async def energy_log_update(
577578
self, address: int | None, save_cache: bool = True
578-
) -> bool:
579+
) -> tuple[bool, bool]:
579580
"""Request energy logs from node and store them.
580581
581-
Return True if processing succeeded: records stored in memory, also for empty slots.
582-
Return False on transport or address errors.
582+
Return first bool as True if processing succeeded: records stored in memory, also with empty slots.
583+
Return fist bool as False on transport or address errors.
584+
Return second bool as False when all slots are empty otherwise as True
583585
"""
586+
result = False
587+
slots_empty = True
584588
if address is None:
585-
return False
589+
return result, slots_empty
586590

587591
_LOGGER.debug(
588592
"Requesting EnergyLogs from node %s address %s",
@@ -595,48 +599,50 @@ async def energy_log_update(
595599
"Retrieving EnergyLogs data from node %s failed",
596600
self._mac_in_str,
597601
)
598-
return False
602+
return result, slots_empty
599603

604+
result = True
600605
_LOGGER.debug("EnergyLogs from node %s, address=%s:", self._mac_in_str, address)
601606
await self._available_update_state(True, response.timestamp)
602607

603608
# Forward historical energy log information to energy counters
604609
# Each response message contains 4 log counters (slots) of the
605610
# energy pulses collected during the previous hour of given timestamp
606611
cache_updated = False
612+
slot_updated = False
607613
for _slot in range(4, 0, -1):
608614
log_timestamp, log_pulses = response.log_data[_slot]
609615
_LOGGER.debug(
610616
"In slot=%s: pulses=%s, timestamp=%s", _slot, log_pulses, log_timestamp
611617
)
612-
if (
613-
log_timestamp is None
614-
or log_pulses is None
615-
# Don't store an old log record; store an empty record instead
616-
or not self._check_timestamp_is_recent(address, _slot, log_timestamp)
617-
):
618+
if log_timestamp is None or log_pulses is None:
618619
self._energy_counters.add_empty_log(response.log_address, _slot)
619-
continue
620-
621-
slot_updated = await self._energy_log_record_update_state(
622-
response.log_address,
623-
_slot,
624-
log_timestamp.replace(tzinfo=UTC),
625-
log_pulses,
626-
import_only=True,
627-
)
620+
elif self._check_timestamp_is_recent(
621+
response.log_address, _slot, log_timestamp.replace(tzinfo=UTC)
622+
):
623+
self._energy_counters.add_pulse_log(
624+
response.log_address,
625+
_slot,
626+
log_timestamp.replace(tzinfo=UTC),
627+
log_pulses,
628+
import_only=True,
629+
)
630+
slot_updated = True
631+
628632
cache_updated |= slot_updated
629633

630634
self._energy_counters.update()
631635
if cache_updated:
636+
slots_empty = False
632637
await self._energy_log_records_save_to_cache()
633638
if save_cache:
634639
_LOGGER.debug(
635640
"Saving and storing energy cache for %s", self._mac_in_str
636641
)
637642
await self.save_cache()
643+
return result, slots_empty
638644

639-
return True
645+
return result, slots_empty
640646

641647
def _check_timestamp_is_recent(
642648
self, address: int, slot: int, timestamp: datetime
@@ -726,48 +732,6 @@ async def _energy_log_records_save_to_cache(self) -> None:
726732
_LOGGER.debug("Updating in-memory energy log records for %s", self._mac_in_str)
727733
self._set_cache(CACHE_ENERGY_COLLECTION, cached_logs)
728734

729-
async def _energy_log_record_update_state(
730-
self,
731-
address: int,
732-
slot: int,
733-
timestamp: datetime,
734-
pulses: int,
735-
import_only: bool = False,
736-
) -> bool:
737-
"""Process new energy log record. Returns true if record is new or changed."""
738-
self._energy_counters.add_pulse_log(
739-
address, slot, timestamp, pulses, import_only=import_only
740-
)
741-
if not self._cache_enabled:
742-
return False
743-
744-
log_cache_record = (
745-
f"{address}:{slot}:{timestamp.strftime('%Y-%m-%d-%H-%M-%S')}:{pulses}"
746-
)
747-
if (cached_logs := self._get_cache(CACHE_ENERGY_COLLECTION)) is not None:
748-
entries = cached_logs.split("|") if cached_logs else []
749-
if log_cache_record not in entries:
750-
_LOGGER.debug(
751-
"Adding logrecord (%s, %s) to cache of %s",
752-
str(address),
753-
str(slot),
754-
self._mac_in_str,
755-
)
756-
return True
757-
758-
_LOGGER.debug(
759-
"Energy logrecord already present for %s, ignoring", self._mac_in_str
760-
)
761-
return False
762-
763-
_LOGGER.debug(
764-
"Cache is empty, adding new logrecord (%s, %s) for %s",
765-
str(address),
766-
str(slot),
767-
self._mac_in_str,
768-
)
769-
return True
770-
771735
@raise_not_loaded
772736
async def set_relay(self, state: bool) -> bool:
773737
"""Change the state of the relay."""

0 commit comments

Comments
 (0)