@@ -74,6 +74,12 @@ def __init__(self, mac, address, message_sender):
7474 self ._energy_last_populated_slot = 0
7575 self ._energy_pulses_current_hour = None
7676 self ._energy_pulses_prev_hour = None
77+ self ._energy_rollover_day_start = False
78+ self ._energy_rollover_day_finished = True
79+ self ._energy_rollover_history_start = False
80+ self ._energy_rollover_history_finished = True
81+ self ._energy_rollover_hour_start = False
82+ self ._energy_rollover_hour_finished = True
7783 self ._energy_pulses_today_hourly = None
7884 self ._energy_pulses_today_now = None
7985 self ._energy_pulses_yesterday = None
@@ -341,9 +347,6 @@ def _response_power_usage(self, message: CirclePowerUsageResponse):
341347 else :
342348 self ._update_energy_current_hour (message .pulse_hour_consumed .value )
343349
344- # Update energy consumption today
345- self ._update_energy_today_now ()
346-
347350 # Power produced current hour
348351 if message .pulse_hour_produced .value == - 1 :
349352 message .pulse_hour_produced .value = 0
@@ -422,82 +425,6 @@ def _collect_energy_pulses(self, start_utc: datetime, end_utc: datetime):
422425 return _energy_pulses
423426 return None
424427
425- def _calc_todays_energy_pulses (self ):
426- """Calculate energy consumption today pulse counter"""
427-
428- if self ._energy_pulses_current_hour is None :
429- return None
430-
431- _current_local_timestamp = datetime .now ()
432- _current_local_hour = _current_local_timestamp .hour
433- _end_utc_timestamp = datetime .utcnow ().replace (
434- minute = 0 , second = 0 , microsecond = 0
435- )
436- _start_utc_timestamp = _end_utc_timestamp - timedelta (
437- hours = _current_local_hour - 1
438- )
439-
440- # Validate if last energy counter is already available to use
441- if self ._energy_last_collected_timestamp != _end_utc_timestamp :
442- _LOGGER .debug (
443- "energy_consumption_today for %s | expected counter (%s) is not available, last available counter (%s)" ,
444- self .mac ,
445- str (_end_utc_timestamp ),
446- str (self ._energy_last_collected_timestamp ),
447- )
448- self ._request_info (self .request_energy_counters )
449- return None
450-
451- # Handle post hour rollover, possible due to small clock drifts
452- if self ._energy_last_local_hour != _current_local_hour :
453- if self ._energy_pulses_current_hour < self ._energy_last_hour_pulses :
454- _LOGGER .debug (
455- "energy_consumption_today for %s | post hour rollover reset (hour:%s=>%s, pulses:%s=>%s)" ,
456- self .mac ,
457- str (self ._energy_last_local_hour ),
458- str (_current_local_hour ),
459- str (self ._energy_last_hour_pulses ),
460- str (self ._energy_pulses_current_hour ),
461- )
462- self ._energy_last_local_hour = _current_local_hour
463- self ._energy_last_hour_pulses = self ._energy_pulses_current_hour
464-
465- # Skip pre hour rollover, possible due to small clock drifts
466- if self ._energy_pulses_current_hour < self ._energy_last_hour_pulses :
467- _LOGGER .debug (
468- "energy_consumption_today for %s | Skip for pre hour rollover" ,
469- self .mac ,
470- )
471- self ._request_info (self .request_energy_counters )
472- return None
473- else :
474- self ._energy_last_hour_pulses = self ._energy_pulses_current_hour
475-
476- # Return current energy counter
477- if _current_local_hour == 0 :
478- return self ._energy_last_hour_pulses
479-
480- # Sum of collected hour counters
481- _energy_pulses = self ._collect_energy_pulses (
482- _start_utc_timestamp , _end_utc_timestamp
483- )
484- if _energy_pulses is None :
485- _LOGGER .debug (
486- "energy_consumption_today for %s | FAILED collecting energy pulses from %s to %s" ,
487- self .mac ,
488- str (_start_utc_timestamp ),
489- str (_end_utc_timestamp ),
490- )
491- return None
492-
493- _energy_use = _energy_pulses + self ._energy_last_hour_pulses
494- _LOGGER .debug (
495- "energy_consumption_today for %s | return %s kWh" ,
496- self .mac ,
497- str (_energy_use ),
498- )
499- return _energy_use
500-
501428 def _update_energy_current_hour (self , _pulses_cur_hour ):
502429 """Update energy consumption (pulses) of current hour"""
503430 _LOGGER .debug (
@@ -506,28 +433,81 @@ def _update_energy_current_hour(self, _pulses_cur_hour):
506433 str (self ._energy_pulses_current_hour ),
507434 str (_pulses_cur_hour ),
508435 )
436+ _hour_rollover = False
509437 if (
510438 self ._energy_pulses_current_hour is None
511439 or self ._energy_pulses_current_hour != _pulses_cur_hour
512440 ):
441+ if _pulses_cur_hour < self ._energy_pulses_current_hour :
442+ _hour_rollover = True
513443 self ._energy_pulses_current_hour = _pulses_cur_hour
514444 self .do_callback (FEATURE_POWER_CONSUMPTION_CURRENT_HOUR ["id" ])
515445
516- def _update_energy_today_now (self ):
446+ # Update today
447+ self ._update_energy_today_now (_hour_rollover , False , False )
448+
449+ def _update_energy_today_now (
450+ self , hour_rollover = False , history_rollover = False , day_rollover = False
451+ ):
517452 """Update energy consumption (pulses) of today up to now"""
518- _pulses_today_now = self ._calc_todays_energy_pulses ()
453+
454+ # Check for rollovers triggers
455+ if hour_rollover and not self ._energy_rollover_hour_finished :
456+ self ._energy_rollover_hour_start = True
457+ if history_rollover and not self ._energy_rollover_history_finished :
458+ self ._energy_rollover_history_start = True
459+ if day_rollover and not self ._energy_rollover_day_finished :
460+ self ._energy_rollover_day_start = True
461+
462+ # Set counter
463+ if self ._energy_rollover_hour_start :
464+ if self ._energy_rollover_history_start :
465+ if self ._energy_rollover_day_start :
466+ # Day rollover, reset to only current hour
467+ _pulses_today_now = self ._energy_last_hour_pulses
468+ self ._energy_rollover_day_start = False
469+ self ._energy_rollover_day_finished = True
470+ else :
471+ # Hour rollover, reset to hour history with current hour
472+ _pulses_today_now = (
473+ self ._energy_pulses_today_hourly
474+ + self ._energy_pulses_current_hour
475+ )
476+ self ._energy_rollover_hour_finished = True
477+ self ._energy_rollover_hour_start = False
478+ self ._energy_rollover_history_finished = True
479+ self ._energy_rollover_history_start = False
480+ else :
481+ # Wait for history_rollover, keep current counter
482+ _pulses_today_now = self ._energy_pulses_today_now
483+ else :
484+ if self ._energy_rollover_history_start :
485+ # Wait for hour_rollover, keep current counter
486+ _pulses_today_now = self ._energy_pulses_today_now
487+ else :
488+ # Regular update
489+ if self ._energy_pulses_today_hourly is None :
490+ _pulses_today_now = None
491+ else :
492+ _pulses_today_now = (
493+ self ._energy_pulses_today_hourly
494+ + self ._energy_pulses_current_hour
495+ )
519496 _LOGGER .debug (
520- "_update_energy_today_now for %s | counter = %s, update= %s" ,
497+ "_update_energy_today_now for %s | counter = %s, update= %s (%s + %s) " ,
521498 self .mac ,
522499 str (self ._energy_pulses_today_now ),
523500 str (_pulses_today_now ),
501+ str (self ._energy_pulses_today_hourly ),
502+ str (self ._energy_pulses_current_hour ),
524503 )
525- if (
526- self ._energy_pulses_today_now is None
527- or self ._energy_pulses_today_now != _pulses_today_now
528- ):
529- self ._energy_pulses_today_now = _pulses_today_now
530- self .do_callback (FEATURE_ENERGY_CONSUMPTION_TODAY ["id" ])
504+ if _pulses_today_now is not None :
505+ if (
506+ self ._energy_pulses_today_now is None
507+ or self ._energy_pulses_today_now != _pulses_today_now
508+ ):
509+ self ._energy_pulses_today_now = _pulses_today_now
510+ self .do_callback (FEATURE_ENERGY_CONSUMPTION_TODAY ["id" ])
531511
532512 def _update_energy_previous_hour (self , prev_hour : datetime ):
533513 """Update energy consumption (pulses) of previous hour"""
@@ -568,7 +548,10 @@ def _update_energy_yesterday(
568548
569549 def _update_energy_today_hourly (self , start_today : datetime , end_today : datetime ):
570550 """Update energy consumption (pulses) of today up to last hour"""
571- _pulses_today_hourly = self ._collect_energy_pulses (start_today , end_today )
551+ if start_today > end_today :
552+ _pulses_today_hourly = 0
553+ else :
554+ _pulses_today_hourly = self ._collect_energy_pulses (start_today , end_today )
572555 _LOGGER .debug (
573556 "_update_energy_today_hourly for %s | counter = %s, update= %s, range %s to %s" ,
574557 self .mac ,
@@ -592,10 +575,7 @@ def request_energy_counters(self, log_address=None, callback=None):
592575 if log_address is None :
593576 log_address = self ._last_log_address
594577 if log_address is not None :
595- if (
596- len (self ._energy_history ) > 48
597- or self ._energy_history_collecting
598- ):
578+ if len (self ._energy_history ) > 48 or self ._energy_history_collecting :
599579 # Energy history already collected
600580 if (
601581 log_address == self ._last_log_address
@@ -666,14 +646,15 @@ def _response_energy_counters(self, message: CircleEnergyCountersResponse):
666646 # Check for midnight rollover
667647 if (
668648 _log_timestamp == _utc_midnight_timestamp
669- and self ._energy_consumption_today_reset != _local_midnight_timestamp
649+ and not self ._energy_rollover_day_finished
670650 ):
671651 _LOGGER .debug (
672652 "_response_energy_counters for %s | midnight rollover, reset date to %s" ,
673653 self .mac ,
674654 str (_local_midnight_timestamp ),
675655 )
676656 self ._energy_consumption_today_reset = _local_midnight_timestamp
657+ self ._update_energy_today_now (False , True , True )
677658
678659 # Store most recent timestamp of collected pulses
679660 if self ._energy_last_collected_timestamp < _log_timestamp :
@@ -694,7 +675,7 @@ def _response_energy_counters(self, message: CircleEnergyCountersResponse):
694675 _utc_midnight_timestamp - timedelta (hours = 23 ),
695676 _utc_midnight_timestamp ,
696677 )
697- self ._update_energy_today_now ()
678+ self ._update_energy_today_now (False , False , False )
698679
699680 # Cleanup energy history for more than 8 day's ago
700681 _8_days_ago = datetime .utcnow ().replace (
0 commit comments