@@ -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