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.
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;
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.
- 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.
- Decoy helper entities (
ha-packages/predbat_alphaess_decoys.yaml) are what Predbat writes its charge/export plan to.apps.yamlmaps Predbat's control keys onto them, and a custom inverter type makes Predbat write the real enable entities rather than internal dummies. 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.
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 entityThe 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 the AlphaESS Modbus TCP integration
(HACS) and confirm you have the AlphaESS
dispatchcontrol entities + telemetry sensors. - Add the decoy helpers — copy
ha-packages/predbat_alphaess_decoys.yamlinto your HApackages/directory (configuration.yaml→homeassistant: packages: !include_dir_named packages), and restart HA. - Install pyscript (HACS) and copy
pyscript/alphaess_glue.pyinto<config>/pyscript/. Set theDISPATCH_*,SENSOR_*andFAULT_SENSORSentity IDs at the top of the file to match your AlphaESS integration. - Configure Predbat — merge
apps.yaml.snippet.yamlinto your Predbatapps.yamland adjust the telemetry entity IDs,soc_max, and rate limits to your system. - Reload pyscript (or restart HA) and Predbat.
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_switchflips on, switch.alphaess_inverter_dispatchturns 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.mdfor safety-first, copy-paste prompts (context, pre-flight checks, and a supervised one-slot live test).
| 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) |
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
pytestCI (.github/workflows/ci.yml) runs py_compile + the suite on every push and PR.
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.pyandapps.yamlagainst 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.
- Predbat by @springfall2008
- AlphaESS Modbus TCP by @senalse
- pyscript