Skip to content

Add GivEnergy EV charger auto-configuration and charge control - #4698

Merged
springfall2008 merged 2 commits into
mainfrom
feat/gecloud-evc-car-control
Aug 24, 2026
Merged

Add GivEnergy EV charger auto-configuration and charge control#4698
springfall2008 merged 2 commits into
mainfrom
feat/gecloud-evc-car-control

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

What

The EV charger poll fetched the charger's status on every cycle and threw it away — only the meter measurands were published — and nothing wired a charger into Predbat's car planning at all. This adds both, plus optional charge control, in the same shape as the myenergi Zappi and Ohme support.

Two new settings, both defaulting to off, so nothing changes for existing users until they ask for it.

Published entities

From data the poll already fetched, so no extra API calls:

Entity Description
sensor.predbat_gecloud_<serial>_evc_status The status as GivEnergy reports it (charging, idle, offline, …)
binary_sensor.predbat_gecloud_<serial>_evc_car_connected on while a car is plugged in

An unrecognised status counts as no car — the safe way round, since a false "connected" would have Predbat plan slots for a car that isn't there — and is logged once per distinct value so it can be added rather than silently ignored.

ge_cloud_automatic_evc (default false)

Wires the chargers into car_charging_energy, car_charging_planned and num_cars, in serial order so charger N is car N.

  • Separate from ge_cloud_automatic on purpose. It registers a car and moves num_cars, which would change the plan for existing users who had only ever asked for their inverter to be configured.
  • Runs whether or not a GivEnergy battery is present, so a charger paired with another manufacturer's battery is configured too — async_automatic_config() returns early with no batteries, so this is a separate call rather than folded into it.
  • car_charging_planned points at the binary sensor rather than the status string because on matches the default car_charging_planned_response. Wiring the raw status would need every user to add GivEnergy's vocabulary to that list. Ohme does the same thing with binary_sensor.predbat_ohme_connected.
  • num_cars is only ever raised, never lowered, matching ohme and octopus — another component may have registered cars of its own.

ge_cloud_evc_control (default false, needs ge_cloud_automatic_evc)

Starts and stops each charger from its car's plan: start-charge inside a planned window, stop-charge outside one.

  • A command is only sent when the wanted state changes — every command goes through async_send_evc_command's 10-retry loop, so re-issuing "keep charging" each minute would be expensive and pointless
  • A charger with no car plugged in is left alone
  • Nothing is sent until Predbat has published a plan, so a restart cannot stop a charge already running
  • switch.predbat_gecloud_evc_control appears when control can act, on by default, persisted through Storage
  • Read only mode and switching it off both release: a charger Predbat had stopped gets one start-charge on the way out, so a car is never stranded

Unlike a Zappi there is no previous mode to restore — start-charge/stop-charge are commands, not modes — so the charger's own mode (Grid/Hybrid/Solar) governs once Predbat lets go. Called out in the code and docs so it doesn't read as a missing feature.

Shared plan parsing

parse_car_plan_windows() and in_car_plan_window() move to utils.py as plain functions. The New Year rollover, malformed-entry skipping and the "no plan published yet" case now live in one place instead of being duplicated. myenergi's behaviour is unchanged — its methods became three-line delegations, and its 18 existing control tests are the regression check.

Testing

Three new test groups in test_ge_cloud.py:

  • publish_evc_device — status→connected across the OCPP vocabulary and casings, once-only logging of an unknown status, no-status publishing nothing
  • automatic_config_evc — multi-charger serial ordering, num_cars raised but never lowered, no-chargers wiring nothing, a charger whose serial hasn't arrived yet skipped
  • evc_control — both gating paths (including that the reason is logged), start on window, no re-send, stop outside, read-only release happening exactly once, switch-off release, empty charger ignored, no-plan ignored, two-charger serial→car ordering

The run-order test also now asserts the control gate: async_automatic_config_evc is absent on a first run with the flag off, then present once enabled. I verified that assertion has teeth by breaking the gate and confirming the test fails.

run_all --quick: 820 passed, 0 failed. Pre-commit clean.

Not verified

GivEnergy's exact status vocabulary — the test fixtures show charging, idle, offline and the rest is extrapolated from OCPP. Anything outside both tables reads as no car and logs once, which is how we'll find out what's missing.

🤖 Generated with Claude Code

The EV charger poll fetched the charger's status on every cycle and threw
it away, publishing only the meter measurands, and nothing wired a charger
into Predbat's car planning at all.

Publishes two entities from data already fetched: _evc_status, the status
as GivEnergy reports it, and _evc_car_connected, a binary sensor derived
from it. An unrecognised status counts as no car - the safe way round - and
is logged once so it can be added rather than silently ignored.

ge_cloud_automatic_evc (default off) wires the chargers into
car_charging_energy, car_charging_planned and num_cars, in serial order so
charger N is car N. It is a separate setting from ge_cloud_automatic
because it registers a car and moves num_cars, which would change the plan
for existing users who had only asked for their inverter to be configured.
It runs whether or not a GivEnergy battery is present, so a charger paired
with another manufacturer's battery is configured too. car_charging_planned
points at the binary sensor rather than the status string because "on"
matches the default car_charging_planned_response, so no response list
needs extending.

ge_cloud_evc_control (default off, needs ge_cloud_automatic_evc) starts and
stops each charger from its car's plan. A command is only sent when the
wanted state changes, a charger with no car plugged in is left alone, and
nothing is sent until a plan has been published so a restart cannot stop a
charge already running. switch.predbat_gecloud_evc_control hands the
charger back without editing apps.yaml, and is persisted. Read only mode
and switching it off both release: a charger Predbat had stopped is started
again on the way out. Unlike a Zappi there is no previous mode to restore -
start-charge and stop-charge are commands, not modes.

The car plan window parsing myenergi already had is now shared, as
parse_car_plan_windows() and in_car_plan_window() in utils.py, so the New
Year rollover and malformed entry handling live in one place. myenergi's
behaviour is unchanged and its existing control tests cover the move.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 24, 2026 10:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

There are two verified control/plan-parsing edge cases that can cause incorrect charger control decisions (New Year window parsing and controlling chargers beyond num_cars before mappings are established).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds first-class support for GivEnergy EV chargers in Predbat: it publishes charger status/connectivity entities, optionally auto-wires chargers into the car-planning inputs, and (optionally) starts/stops charging based on the published car plan—mirroring the existing Zappi/Ohme shape. It also centralizes car-plan window parsing into shared utilities to avoid duplicated logic across charger integrations.

Changes:

  • Add GivEnergy EV charger status publishing, optional auto-configuration into car planning, and optional plan-driven start/stop control (with a persisted runtime enable switch).
  • Refactor shared car-plan window parsing/matching into utils.py, and update myenergi to delegate to the shared helpers.
  • Add documentation and unit tests for the new GivEnergy EV charger behavior, plus cspell dictionary updates.
File summaries
File Description
docs/components.md Documents new GivEnergy EV charger entities, auto-wiring, and control behavior.
docs/apps-yaml.md Documents new ge_cloud_automatic_evc and ge_cloud_evc_control settings and their effects.
apps/predbat/utils.py Introduces shared car-plan window parsing/matching helpers for charger-control components.
apps/predbat/gecloud.py Implements EV charger status publishing, auto-wiring into car planning, and plan-driven charge control with persisted runtime switch.
apps/predbat/config.py Adds schema entries for the new GivEnergy EVC config flags.
apps/predbat/components.py Wires the new GivEnergy EVC flags into the component argument mapping.
apps/predbat/tests/test_ge_cloud.py Adds/extends tests for EVC publishing, auto-config wiring, and control behavior.
apps/predbat/myenergi.py Replaces local plan parsing with calls into the new shared utils helpers.
.cspell/custom-dictionary-workspace.txt Adds charger-status vocabulary tokens for spell-checking.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/predbat/utils.py Outdated
Comment thread apps/predbat/gecloud.py
A car charging window spanning New Year was matched before midnight but
not after it. Read at 00:30 on 1 January, a 12-31 start parses as December
of the year just started - eleven months ahead - and the rebuild only
handled windows that landed in the past, so the window read as not yet
started and the car was stopped mid-charge. The rebuild is now symmetric.

The margin that decides a year is wrong moves from 23 hours to 180 days.
23 hours is inside the 48 hour horizon a plan covers, so shifting on it
would have dragged a window 30 hours ahead back into the previous year;
180 days cannot collide with a real window but always catches a year that
was stamped on wrongly.

evc_control_charge() mapped every charger to a car index and stopped any
whose index had no plan. num_cars is raised by async_automatic_config_evc,
but that reaches the base object a cycle later, so a second charger could
be stopped while its car was charging. Control now runs only as far as
there are cars, leaving a charger with no plan alone.

Both cases are covered by tests that fail without the fixes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@springfall2008
springfall2008 merged commit 8a7dce0 into main Aug 24, 2026
2 checks passed
@springfall2008
springfall2008 deleted the feat/gecloud-evc-car-control branch August 24, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants