@@ -364,7 +364,7 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
364364
365365 # Always request last energy log records at initial startup
366366 if not self ._last_energy_log_requested :
367- self ._last_energy_log_requested , _ = await self .energy_log_update (
367+ self ._last_energy_log_requested = await self .energy_log_update (
368368 self ._current_log_address
369369 )
370370
@@ -378,7 +378,7 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
378378 return None
379379
380380 # Try collecting energy-stats for _current_log_address
381- result , _ = await self .energy_log_update (self ._current_log_address )
381+ result = await self .energy_log_update (self ._current_log_address )
382382 if not result :
383383 _LOGGER .debug (
384384 "async_energy_update | %s | Log rollover | energy_log_update failed" ,
@@ -392,7 +392,7 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
392392 _prev_log_address , _ = calc_log_address (
393393 self ._current_log_address , 1 , - 4
394394 )
395- result , _ = await self .energy_log_update (_prev_log_address )
395+ result = await self .energy_log_update (_prev_log_address )
396396 if not result :
397397 _LOGGER .debug (
398398 "async_energy_update | %s | Log rollover | energy_log_update %s failed" ,
@@ -413,7 +413,7 @@ async def energy_update(self) -> EnergyStatistics | None: # noqa: PLR0911 PLR09
413413 return self ._energy_counters .energy_statistics
414414
415415 if len (missing_addresses ) == 1 :
416- result , _ = await self .energy_log_update (missing_addresses [0 ])
416+ result = await self .energy_log_update (missing_addresses [0 ])
417417 if result :
418418 await self .power_update ()
419419 _LOGGER .debug (
@@ -464,52 +464,15 @@ async def _get_initial_energy_logs(self) -> None:
464464 log_address = self ._current_log_address
465465 prev_address_timestamp : datetime | None = None
466466 while total_addresses > 0 :
467- result , empty_log = await self .energy_log_update (log_address )
468- if result and empty_log :
467+ result = await self .energy_log_update (log_address )
468+ if not result :
469469 # Handle case with None-data in all address slots
470470 _LOGGER .debug (
471- "Energy None-data collected from log address %s, stopping collection" ,
471+ "All slots at log address %s are empty or outdated – stopping initial collection" ,
472472 log_address ,
473473 )
474474 break
475475
476- # Check if the most recent timestamp of an earlier address is recent
477- # (within 2/4 * log_interval plus 5 mins margin)
478- log_interval = self .energy_consumption_interval
479- factor = 2 if self .energy_production_interval is not None else 4
480-
481- if log_interval is not None :
482- max_gap_minutes = (factor * log_interval ) + 5
483- if log_address == self ._current_log_address :
484- if (
485- self ._last_collected_energy_timestamp is not None
486- and (
487- datetime .now (tz = UTC ) - self ._last_collected_energy_timestamp
488- ).total_seconds ()
489- // 60
490- > max_gap_minutes
491- ):
492- _LOGGER .debug (
493- "Energy data collected from the current log address is outdated, stopping collection"
494- )
495- break
496- elif (
497- prev_address_timestamp is not None
498- and self ._last_collected_energy_timestamp is not None
499- and (
500- prev_address_timestamp - self ._last_collected_energy_timestamp
501- ).total_seconds ()
502- // 60
503- > max_gap_minutes
504- ):
505- _LOGGER .debug (
506- "Collected energy data is outdated, stopping collection"
507- )
508- break
509-
510- if self ._last_collected_energy_timestamp is not None :
511- prev_address_timestamp = self ._last_collected_energy_timestamp
512-
513476 log_address , _ = calc_log_address (log_address , 1 , - 4 )
514477 total_addresses -= 1
515478
@@ -544,30 +507,27 @@ async def get_missing_energy_logs(self) -> None:
544507 if self ._cache_enabled :
545508 await self ._energy_log_records_save_to_cache ()
546509
547- async def energy_log_update (self , address : int | None ) -> tuple [bool , bool ]:
548- """Request energy log statistics from node. Returns true if successful."""
549- empty_log = False
550- result = False
510+ async def energy_log_update (self , address : int | None ) -> bool :
511+ """Request energy logs and return True only when at least one recent, non-empty record was stored; otherwise return False."""
512+ any_record_stored = False
551513 if address is None :
552- return result , empty_log
514+ return False
553515
554516 _LOGGER .debug (
555- "Request of energy log at address %s for node %s" ,
556- str ( address ) ,
557- self . name ,
517+ "Requesting EnergyLogs from node %s address %s" ,
518+ self . _mac_in_str ,
519+ address ,
558520 )
559521 request = CircleEnergyLogsRequest (self ._send , self ._mac_in_bytes , address )
560522 if (response := await request .send ()) is None :
561523 _LOGGER .debug (
562- "Retrieving of energy log at address %s for node %s failed" ,
563- str (address ),
524+ "Retrieving EnergyLogs data from node %s failed" ,
564525 self ._mac_in_str ,
565526 )
566- return result , empty_log
527+ return False
567528
568- _LOGGER .debug ("EnergyLogs data from %s, address=%s" , self ._mac_in_str , address )
529+ _LOGGER .debug ("EnergyLogs from node %s, address=%s: " , self ._mac_in_str , address )
569530 await self ._available_update_state (True , response .timestamp )
570- energy_record_update = False
571531
572532 # Forward historical energy log information to energy counters
573533 # Each response message contains 4 log counters (slots) of the
@@ -578,17 +538,23 @@ async def energy_log_update(self, address: int | None) -> tuple[bool, bool]:
578538 _LOGGER .debug (
579539 "In slot=%s: pulses=%s, timestamp=%s" , _slot , log_pulses , log_timestamp
580540 )
581- if log_timestamp is None or log_pulses is None :
541+ if (
542+ log_timestamp is None
543+ or log_pulses is None
544+ # Don't store an old log-record, store am empty record instead
545+ or not self ._check_timestamp_is_recent (address , _slot , log_timestamp )
546+ ):
582547 self ._energy_counters .add_empty_log (response .log_address , _slot )
583- empty_log = True
584- elif await self ._energy_log_record_update_state (
548+ continue
549+
550+ if await self ._energy_log_record_update_state (
585551 response .log_address ,
586552 _slot ,
587553 log_timestamp .replace (tzinfo = UTC ),
588554 log_pulses ,
589555 import_only = True ,
590556 ):
591- energy_record_update = True
557+ any_record_stored = True
592558 if not last_energy_timestamp_collected :
593559 # Collect the timestamp of the most recent response
594560 self ._last_collected_energy_timestamp = log_timestamp .replace (
@@ -600,15 +566,35 @@ async def energy_log_update(self, address: int | None) -> tuple[bool, bool]:
600566 )
601567 last_energy_timestamp_collected = True
602568
603- result = True
604569 self ._energy_counters .update ()
605- if energy_record_update :
570+ if any_record_stored :
606571 _LOGGER .debug (
607572 "Saving energy record update to cache for %s" , self ._mac_in_str
608573 )
609574 await self .save_cache ()
610575
611- return result , empty_log
576+ return any_record_stored
577+
578+ def _check_timestamp_is_recent (
579+ self , address : int , slot : int , timestamp : datetime
580+ ) -> bool :
581+ """Check if the timestamp of the received log-record is recent.
582+
583+ A timestamp from within the last 24 hours is considered recent.
584+ """
585+ age_seconds = (
586+ datetime .now (tz = UTC ) - timestamp .replace (tzinfo = UTC )
587+ ).total_seconds ()
588+ if age_seconds > DAY_IN_HOURS * 3600 :
589+ _LOGGER .warning (
590+ "EnergyLog from Node %s | address %s | slot %s | timestamp %s is outdated, ignoring..." ,
591+ self ._mac_in_str ,
592+ address ,
593+ slot ,
594+ timestamp ,
595+ )
596+ return False
597+ return True
612598
613599 async def _energy_log_records_load_from_cache (self ) -> bool :
614600 """Load energy_log_record from cache."""
0 commit comments