Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion packages/helpermodules/update_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

class UpdateConfig:

DATASTORE_VERSION = 107
DATASTORE_VERSION = 108

valid_topic = [
"^openWB/bat/config/bat_control_permitted$",
Expand Down Expand Up @@ -2724,3 +2724,14 @@ def upgrade(topic: str, payload) -> None:
return {topic: provider}
self._loop_all_received_topics(upgrade)
self._append_datastore_version(107)

def upgrade_datastore_108(self) -> None:
def upgrade(topic: str, payload) -> None:
if re.search("openWB/chargepoint/[0-9]+/set/log$", topic) is not None:
log_data = decode_payload(payload)
if log_data.get("time_charged") is not None:
if isinstance(log_data["time_charged"], str):
log_data["time_charged"] = 0

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

time_charged in chargepoint set/log payload is defined as numeric seconds (see control/chargepoint/chargepoint_data.py Log.time_charged: float). This migration currently replaces any string value with 0, which discards the previously accumulated charging duration and can reset in-progress statistics after an update/restart. Consider converting known string formats instead (e.g. numeric strings via float(...), or H:MM / D:H:MM into seconds) and only falling back to 0.0 when parsing fails.

Suggested change
log_data["time_charged"] = 0
raw_value = log_data["time_charged"]
seconds = 0.0
if raw_value is not None and raw_value != "":
# Try simple numeric representation first
try:
seconds = float(raw_value)
except (TypeError, ValueError):
# Try H:MM format (hours:minutes)
match_h_mm = re.fullmatch(r"(\d+):(\d+)", raw_value)
if match_h_mm is not None:
hours_str, minutes_str = match_h_mm.groups()
try:
hours = int(hours_str)
minutes = int(minutes_str)
seconds = float((hours * 60 + minutes) * 60)
except ValueError:
seconds = 0.0
else:
# Try D:H:MM format (days:hours:minutes)
match_d_h_mm = re.fullmatch(r"(\d+):(\d+):(\d+)", raw_value)
if match_d_h_mm is not None:
days_str, hours_str, minutes_str = match_d_h_mm.groups()
try:
days = int(days_str)
hours = int(hours_str)
minutes = int(minutes_str)
total_hours = days * 24 + hours
seconds = float((total_hours * 60 + minutes) * 60)
except ValueError:
seconds = 0.0
log_data["time_charged"] = seconds

Copilot uses AI. Check for mistakes.

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New datastore upgrade logic (upgrade_datastore_108) isn’t covered by tests. There is already packages/helpermodules/update_config_test.py covering datastore upgrades (e.g., upgrade_datastore_94), so adding a small test that feeds all_received_topics with an openWB/chargepoint/<n>/set/log payload where time_charged is a string and asserts it is converted to the expected numeric seconds would help prevent regressions.

Suggested change
log_data["time_charged"] = 0
value = log_data["time_charged"]
seconds = 0
if value.isdigit():
seconds = int(value)
else:
parts = value.split(":")
try:
if len(parts) == 3:
hours, minutes, secs = map(int, parts)
seconds = hours * 3600 + minutes * 60 + secs
elif len(parts) == 2:
minutes, secs = map(int, parts)
seconds = minutes * 60 + secs
except ValueError:
seconds = 0
log_data["time_charged"] = seconds

Copilot uses AI. Check for mistakes.
return {topic: log_data}
Comment on lines +2729 to +2735

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner upgrade() callback is annotated as returning None, but it conditionally returns a dict of modified topics. For consistency with most other datastore upgrades in this file (which use Optional[dict] for callbacks passed to _loop_all_received_topics) and to avoid misleading type checking, update the return annotation accordingly.

Copilot uses AI. Check for mistakes.
self._loop_all_received_topics(upgrade)
self._append_datastore_version(108)