Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions .cspell/custom-dictionary-workspace.txt
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,8 @@ substep
sunspec
sunsynk
supabase
suspendedev
suspendedevse
synkctl
syscmd
sysdn
Expand Down
10 changes: 10 additions & 0 deletions apps/predbat/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@
"default": False,
"config": "ge_cloud_automatic",
},
"automatic_evc": {
"required": False,
"default": False,
"config": "ge_cloud_automatic_evc",
},
"evc_control": {
"required": False,
"default": False,
"config": "ge_cloud_evc_control",
},
},
"phase": 1,
},
Expand Down
2 changes: 2 additions & 0 deletions apps/predbat/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,8 @@
"ge_cloud_direct": {"type": "boolean"},
"ge_cloud_automatic": {"type": "boolean"},
"ge_cloud_load_today_ignore": {"type": "boolean"},
"ge_cloud_automatic_evc": {"type": "boolean"},
"ge_cloud_evc_control": {"type": "boolean"},
"ge_cloud_automatic_shared_ct": {"type": "boolean"},
"ge_cloud_automatic_split_ct": {"type": "boolean"},
"ge_cloud_automatic_split_pv": {"type": "boolean"},
Expand Down
306 changes: 304 additions & 2 deletions apps/predbat/gecloud.py

Large diffs are not rendered by default.

25 changes: 3 additions & 22 deletions apps/predbat/myenergi.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

import argparse
import asyncio
import datetime
import time
from abc import ABC, abstractmethod
from dataclasses import dataclass
Expand All @@ -37,6 +36,7 @@
from mock_base import MockBase
from oauth_mixin import OAuthMixin
from predbat_metrics import record_api_call
from utils import parse_car_plan_windows, in_car_plan_window

MYENERGI_DIRECTOR_URL = "https://director.myenergi.net"
MYENERGI_CLOUD_URL = "https://api.s18.myenergi.net"
Expand Down Expand Up @@ -112,10 +112,6 @@
# Boosting a Zappi is only accepted while it is in one of the green-energy modes.
ZAPPI_BOOSTABLE_MODES = ("Eco", "Eco+")

# How output.py formats the start/end of each planned car charging window. It carries no
# year, so a parsed window has to be rebuilt around the current time.
PLAN_TIME_FORMAT = "%m-%d %H:%M:%S"

# The two modes Predbat-led charge control drives a Zappi between, and the mode a
# released Zappi falls back to when nothing was saved to restore.
ZAPPI_MODE_CHARGING = "Fast"
Expand Down Expand Up @@ -884,26 +880,11 @@ def refresh_car_windows(self, now):

def _parse_plan_windows(self, planned, now):
"""Turn one car's published plan into a list of localised (start, end) pairs."""
parsed = []
for window in planned:
try:
start = self.local_tz.localize(datetime.datetime.strptime(window["start"], PLAN_TIME_FORMAT).replace(year=now.year))
end = self.local_tz.localize(datetime.datetime.strptime(window["end"], PLAN_TIME_FORMAT).replace(year=now.year))
except (KeyError, TypeError, ValueError):
# One malformed entry must not cost the rest of the plan
continue
# The plan carries no year, so rebuild it around now for windows crossing New Year
if start < now - datetime.timedelta(hours=23):
start = start.replace(year=start.year + 1)
end = end.replace(year=end.year + 1)
elif end < start:
end = end.replace(year=end.year + 1)
parsed.append((start, end))
return parsed
return parse_car_plan_windows(planned, now, self.local_tz)

def should_charge_now(self, car_n, now):
"""Is now inside one of the planned charging windows for this car."""
return any(start <= now < end for start, end in self.control_windows.get(car_n, []))
return in_car_plan_window(self.control_windows.get(car_n, []), now)

def enable_control(self):
"""Decide whether Predbat-led Zappi control should run, and say why when it will not.
Expand Down
Loading
Loading