Skip to content

Repository files navigation

predbat-alphaess-modbus

Drive an AlphaESS battery with Predbat over local Modbus — no cloud, no natively-supported inverter type.

Predbat has no native AlphaESS support. This is a working bridge: Predbat writes its plan to a set of "decoy" Home Assistant helper entities, and a small pyscript script translates that plan into real AlphaESS dispatch commands via the AlphaESS Modbus TCP HACS integration (by @senalse).

Warning

Unofficial and experimental — use entirely at your own risk. This sends real charge/discharge dispatch commands to your inverter over local Modbus. Misconfiguration (wrong entity IDs, wrong limits, an untested integration version) can drive the battery incorrectly and, worst case, stress your hardware or void your warranty. Not affiliated with or endorsed by AlphaESS, Predbat, or the integration author. Read Safety & disclaimer before you let it control anything.

Provided as-is, as a reference for others in the same boat. Entity IDs and a few values are specific to my install — adjust them to yours. Tested on an AlphaESS SMILE-G3-S5 (13.68 kWh), Predbat v8.54.x, AlphaESS Modbus TCP v1.14.

How it works — three layers

flowchart TD
    P["<b>Predbat</b><br/>custom inverter_type"]
    D["<b>Decoy helper entities</b><br/>input_boolean / input_datetime / input_number<br/>+ template switches"]
    G["<b>alphaess_glue.py</b> (pyscript)<br/>stage fields → flip dispatch switch to commit<br/>charge · export · freeze · target-reached · faults · reconcile"]
    I["<b>AlphaESS Modbus TCP</b><br/>HACS integration"]
    B["<b>AlphaESS inverter + battery</b>"]

    P -->|"writes plan:<br/>scheduled_*_enable, start/end times,<br/>rates, target SoC"| D
    D -->|"watched by"| G
    G -->|"dispatch: mode / power /<br/>duration / stop-at-SoC / enable"| I
    I -->|"Modbus TCP over LAN"| B
    B -.->|"telemetry sensors<br/>(SoC, power, grid, PV)"| P

    classDef ha fill:#e8f0fe,stroke:#4285f4,color:#111;
    classDef hw fill:#e6f4ea,stroke:#34a853,color:#111;
    class P,D,G,I ha;
    class B hw;
Loading

The dashed line is telemetry: the AlphaESS sensors flow back to Predbat so it can plan against real SoC / power / grid / PV. Everything above the inverter runs inside Home Assistant; the only link to hardware is local Modbus.

  1. AlphaESS Modbus TCP integration exposes the inverter to Home Assistant, including a dispatch control block (mode / power / duration / stop-at-SoC / enable) and telemetry sensors.
  2. Decoy helper entities (ha-packages/predbat_alphaess_decoys.yaml) are what Predbat writes its charge/export plan to. apps.yaml maps Predbat's control keys onto them, and a custom inverter type makes Predbat write the real enable entities rather than internal dummies.
  3. alphaess_glue.py (pyscript) watches the decoys and translates the plan into real dispatch: stage the fields, then flip the dispatch switch to commit. It handles charge, export, freeze, target-reached release, faults, power clamping, and reconciliation on HA/Predbat restart.

The key gotcha: custom inverter type

If you point Predbat at a built-in inverter_type that doesn't match your inverter's capabilities, Predbat silently creates a dummy entity for each unsupported capability and ignores your apps.yaml mapping. With GE, has_discharge_enable_time is False, so forced export is routed via inverter-mode and the real scheduled_discharge_enable entity is never written — charging works, export silently doesn't.

The fix is a custom inverter type (any non-built-in name → Predbat copies GE as the base, then merges your overrides):

  inverter_type: "AlphaESS_Modbus"
  inverter:
    has_ge_inverter_mode: false        # let Predbat auto-create the inverter_mode decoy
    has_discharge_enable_time: true     # write the REAL scheduled_discharge_enable entity

The only visible clue when it's wrong is an easy-to-miss validation warning: ... element sensor.predbat_GE_0_scheduled_discharge_enable returned value 'None'.

Install

  1. Install the AlphaESS Modbus TCP integration (HACS) and confirm you have the AlphaESS dispatch control entities + telemetry sensors.
  2. Add the decoy helpers — copy ha-packages/predbat_alphaess_decoys.yaml into your HA packages/ directory (configuration.yamlhomeassistant: packages: !include_dir_named packages), and restart HA.
  3. Install pyscript (HACS) and copy pyscript/alphaess_glue.py into <config>/pyscript/. Set the DISPATCH_*, SENSOR_* and FAULT_SENSORS entity IDs at the top of the file to match your AlphaESS integration.
  4. Configure Predbat — merge apps.yaml.snippet.yaml into your Predbat apps.yaml and adjust the telemetry entity IDs, soc_max, and rate limits to your system.
  5. Reload pyscript (or restart HA) and Predbat.

Verify it's working

Force a slot with select.predbat_manual_charge / select.predbat_manual_export for the current half-hour and watch, independently of what Predbat reports:

  • the real switch.predbat_scheduled_charge_enable_switch / ..._discharge_enable_switch flips on,
  • switch.alphaess_inverter_dispatch turns on with a sensible dispatch power,
  • battery SoC actually moves (rises on charge, falls on export) — check the AlphaESS app too.

If SoC doesn't move and the enable switch stays off despite the plan, you're almost certainly hitting the dummy-entity trap above — check your inverter_type / inverter: overrides.

Verified on my install: forced charge, forced export (incl. a sustained run), export-freeze/hold, power-clamp (drops to the AC limit with a warning), and clean reconciliation across pyscript reloads and Predbat restarts mid-dispatch.

Setting this up with an AI assistant? See AI-ASSISTANT.md for safety-first, copy-paste prompts (context, pre-flight checks, and a supervised one-slot live test).

Files

File Purpose
pyscript/alphaess_glue.py The translation glue (pyscript)
ha-packages/predbat_alphaess_decoys.yaml Decoy helper entities + template switches
apps.yaml.snippet.yaml Predbat apps.yaml inverter/control/telemetry section
AI-ASSISTANT.md Copy-paste prompts for setting up & testing safely with an AI assistant
tests/ Unit tests for the glue's time-window logic (pytest)

Tests

The glue's time-window logic — the part where subtle bugs keep appearing (a stale flag reopening a ~24h dispatch; export firing ~30 min early) — has a small pytest suite as regression protection. It doesn't try to mock the hardware dispatch or triggers (that's what the live manual-slot checks in AI-ASSISTANT.md are for); it locks down the pure logic: _parse_time_of_day, _in_window, _minutes_remaining (incl. midnight-crossing) and _clamp_power.

alphaess_glue.py is a pyscript module and isn't normally importable, so tests/conftest.py loads it with pyscript's globals stubbed and a frozen clock — the shipped glue stays byte-identical to what runs in Home Assistant.

pip install -r requirements-dev.txt
pytest

CI (.github/workflows/ci.yml) runs py_compile + the suite on every push and PR.

Safety & disclaimer

This is a hobbyist bridge shared in good faith, as-is and with no warranty of any kind (see LICENSE). It is not affiliated with, endorsed by, or supported by AlphaESS, Predbat / @springfall2008, or the AlphaESS Modbus TCP integration author.

It takes direct control of a high-power battery system — it writes dispatch commands (mode / power / duration / target SoC / enable) to your inverter over local Modbus. Getting it wrong can mean charging or discharging at the wrong times, draining the battery, unwanted grid import/export, or in the worst case stressing hardware or voiding your inverter's warranty.

Important

You install and run this entirely at your own risk. By using it you accept full and sole responsibility for everything it does to your inverter, battery, home, and energy bills. The author and any contributors accept no responsibility or liability whatsoever for any damage, malfunction, loss, cost, warranty issue, or injury arising from its use. If anything goes wrong, that's on you, not me. If you're not comfortable reading the glue and understanding what each dispatch does, do not run it.

Before you let it control anything:

  • Understand your inverter's dispatch / Modbus control model and its limits. Writing the wrong registers can misconfigure the inverter.
  • Verify every entity ID in alphaess_glue.py and apps.yaml against your install — the names here are examples and will differ.
  • Set correct limits (battery_rate_max, the inverter/AC limits, reserve). Wrong limits are how you get out-of-range dispatch writes.
  • Test with manual slots first (predbat_manual_charge / predbat_manual_export) for a single half-hour and watch the battery SoC actually move — don't trust the log alone. Keep runs short until you're confident.
  • Know how to stop it — turning off the enable / dispatch switch reverts the inverter to normal self-consumption.
  • Supervise it. The glue has fail-safes (treats fault sensors and unreadable state as "stop", and freeze dispatches expire within minutes if HA/pyscript dies), but these are not a substitute for keeping an eye on it, especially at first.

Credits

About

Drive an AlphaESS battery with Predbat over local Modbus (decoy entities + pyscript glue)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages