Skip to content

Commit 2c74e84

Browse files
committed
Simplify energy today counter rollovers
1 parent 6e57f52 commit 2c74e84

File tree

1 file changed

+76
-95
lines changed

1 file changed

+76
-95
lines changed

plugwise/nodes/circle.py

Lines changed: 76 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)