
ioBroker.sunenergyxt500
Tests:
sunenergyxt500 adapter for ioBroker
Integration and self-consumption control for SunEnergyXT 500 / 500 PRO AC-coupled hybrid battery storage systems via the device's local HTTP API — no cloud account required. One instance manages up to three heads (storage towers).
Language / Sprache
Features
- Manages one to three heads in a single instance, each under its own subtree
heads.<n>.*, plus combinedtotal.*aggregates. - Polls the local API (
GET /read) and mirrors all stable fields to states: SoC, battery/grid/load/PV power, per-MPPT current/voltage, daily energy counters, per-pack SoC, device/firmware info and meter status. - Writable control fields (
POST /write, confirmed by re-reading), matching the official integration's control surface except fields the API docs mark as reserved: grid setpointGS, max feed-inIS, SoC limitsSI/SA/SO, self-consumption modeMM, meter configMD, timezoneTZ, restartRT, max grid outputMG, theLFB/LPS/PMswitches and local modeLM(LM=1blocks cloud/app control until reset). Reserved fields (e.g.PT,SI1,SA1) are exposed read-only only. - Two switchable control modes: an adapter-side self-consumption controller (writes
GSfrom any ioBroker meter state, feed-forward + P, with watchdog/failsafe) that splits one grid setpoint across all heads, or device self-regulation (binds a supported meter into a single storage and lets the device control itself) — plus an off mode for pure monitoring. - A "Test all heads" button in the admin checks reachability of each configured head (model + SoC) before you save.
- Connection indicator (
info.connection) plusinfo.lastUpdate, and per-headonline/lastError. - The complete, unmodified
/readresponse of each head is kept inheads.<n>.info.rawResponse(JSON), so any field the adapter does not map to a dedicated state can still be read from there.
How this adapter works
This adapter controls the storage locally, without the manufacturer cloud. A single instance manages one to three heads (storage towers). Self-consumption can be handled in two mutually exclusive ways — you pick one via the Control mode setting:
Mode B — Adapter controller (default-recommended, works with any meter, 1–3 heads). ioBroker reads the current grid power from any state you point it at (gridPowerStateId) and the adapter writes the grid setpoint GS (feed-forward + P correction, with a watchdog). The meter can be anything ioBroker supports — Shelly, Tasmota, a smart-meter/Modbus adapter — including meters the storage cannot read itself. You provide one state holding the net grid power in watts (>0 = draw, <0 = feed-in; enable invert source sign if reversed; for kW / split import-export / per-phase meters compute a clean net value in a small ioBroker state first). With more than one head, the controller computes one total setpoint and splits it across the online heads — equally, capped at each head's power, and skipping a head that is full (while charging) or empty (while discharging); its share is redistributed to the others. The adapter forces MM=0 on every head so the devices execute GS, and the meter stays fully usable in ioBroker.
Mode A — Device self-regulation (supported meters, single head only). The adapter binds a supported meter into the storage (MM=1 + MD) and lets the device regulate itself — the manufacturer's own self-consumption, which may react faster than an external loop. This mode is available only with a single head; with two or three heads configured it cannot be selected — use the adapter controller instead. Only four meter types are supported (EcoTracker, Shelly 3EM, Shelly Pro 3EM, Tasmota) and the meter must be reachable by the storage on the LAN. The adapter does not write GS in this mode. The binding is just mDNS/HTTP polling, so the meter stays usable in ioBroker — unlike the manufacturer app's meter setup, which can reconfigure the meter and remove it from ioBroker; this adapter binds directly and avoids that.
Off (default, monitoring only). The adapter never writes MM/MD/GS; it only polls. You can still command control.* states manually.
In both control modes the adapter owns MM: on every poll it checks each head's MM against the chosen mode and re-asserts it (with a warning) if something else changed it — so a stray meter binding or an external script cannot silently disable control. Note: a head only executes a written GS when MM=0; with a meter bound (MM=1) it self-regulates and ignores GS.
Multiple heads must be on different phases. This is the operator's electrical responsibility — the adapter does not (and cannot) verify it. The controller regulates the net (summed) grid power your meter reports, which is what a standard netting German bidirectional meter bills; per-phase optimisation is out of scope.
Local mode (LM=1) is required. Each device only serves its local HTTP API (/read / /write) when local mode is enabled — with it off, /read returns no data (confirmed on the tested firmware). Enabling local mode also switches off cloud/app remote control; consequently the manufacturer's phone app can no longer control the device.
Requirements
- One to three SunEnergyXT 500 (
PK=1, 800 W) or 500 PRO (PK=2, 2400 W) heads reachable in the local network (mixed models are fine). - Local mode (
LM=1) enabled on each device — required for the local HTTP API to deliver values (see How this adapter works). This also disables cloud/app remote control. - A meter, depending on the control mode: for Mode B (adapter controller) any meter whose grid power is available as an ioBroker state; for Mode A (device self-regulation, single head) one of the four supported meters (EcoTracker, Shelly 3EM, Shelly Pro 3EM, Tasmota) reachable by the storage on the LAN. Not needed in Off mode.
Installation
- In ioBroker admin open Adapters, search for sunenergyxt500 and install it.
- After installation an instance
sunenergyxt500.0is created. Open its settings and enter the Head 1 IP / hostname (add Head 2 / Head 3 if you have more heads). Leave the Control mode at Off for pure monitoring. - Save & close — the adapter starts polling and fills the object tree under
sunenergyxt500.0.heads.*(andtotal.*).
Configuration
Connection
- Head 1 IP / hostname (required) and Head 2 / Head 3 (optional) — local addresses of your storage heads, each with an optional label. Up to three heads are managed by this single instance. Put multiple heads on different phases (operator's responsibility); the adapter regulates the net summed grid power. The same address cannot be entered twice.
- Test all heads — probes each configured head and reports model + SoC (or an error), so you can verify the addresses before saving.
- Poll interval (s) — how often each head is queried via
/read(default 5 s). - Request timeout (ms) — HTTP timeout (default 8000 ms).
Control — pick a Control mode:
Off (default) — monitoring only; the adapter never writes MM/MD/GS.
Adapter controller (Mode B) — fields:
- Grid-power source state — a foreign state holding your house meter's grid power. Convention:
>0= grid draw,<0= feed-in. Enable Invert source sign if your meter uses the opposite convention. - Gain (default 0.3), Dead band (W), Min. write interval (ms), Per-head write dead band (W — minimum change of a head's setpoint before it is re-written, to avoid chatter as the split shifts). Each head's maximum power is detected automatically from the device (800 W for a 500, 2400 W for a 500 PRO), so mixed setups work without extra configuration.
- Watchdog warn / failsafe (s) — if the grid source goes stale, the controller logs a warning and finally forces
GS=0on all heads (safe neutral) until the source recovers. Watchdog telemetry is exposed undercontroller.*.
The controller reads each device's actual grid power (GP) back before correcting, which provides natural anti-windup when a device internally limits (e.g. by SoC).
Device self-regulation (Mode A, single head only) — fields:
- Meter type — EcoTracker / Shelly 3EM / Shelly Pro 3EM / Tasmota.
- Meter SN / IP — the serial number for Shelly/Tasmota (resolved via mDNS), or the LAN IP for EcoTracker (direct). For Tasmota use the SN prefix without the last 4 characters and set the power key matching your energy-monitor subtype.
The adapter binds the meter (MM=1 + MD) and the device regulates itself; the adapter does not write GS. The bound meter stays usable in ioBroker. This mode is hidden/blocked once a second or third head is configured.
Safety: In Off mode the adapter is read-only — it only polls
/readand never writes unless you command acontrol.*state. In a control mode the adapter enforcesMMon every head for that mode and re-asserts it if changed externally; do not run a secondGSwriter at the same time (your own script, or a device'sMMwith a different meter), otherwise they fight over the battery.
Sign conventions
GP(grid power):>0= feed-in,<0= draw — opposite to a Shelly meter (api.GP ≈ −shelly.gridPower).BP(battery power):>0= charging,<0= discharging.GS(grid setpoint):>0= feed-in/discharge,<0= grid charging (±2400 W on the Pro, 10 W steps).
Object tree
Each head gets its own subtree under heads.<n>.* (n = 1…3), plus combined total.* aggregates and adapter-level controller.* / info.*. Within a head, states are grouped into thematic channels; the leaf of each object id is the device's API field code (the entity id from the official field reference), and the bilingual object name describes it — so the tree maps 1:1 to the device's documented fields.
| Channel | Contents |
|---|---|
heads.<n>.battery.* |
SoC (SC), battery power (BP), per-pack SoC (SC0–SC5), online packs (ON), SoC hysteresis (SI1/SA1) |
heads.<n>.grid.* |
grid power (GP), daily charge/feed-in energy (GD1/GD2) |
heads.<n>.load.* |
load power (LP), daily off-grid load energy (LD) |
heads.<n>.pv.* |
total PV (PV) and per-MPPT power/current/voltage (mppt1–mppt4) |
heads.<n>.system.* |
total input/output power (IW/OP) |
heads.<n>.device.* |
type/model/serial/status; network.* (IP, port, Wi-Fi); firmware.* (ES/AS/DS software, EH/AH/DH hardware, BS0–BS5 BMS) |
heads.<n>.meter.* |
external meter status (MS) |
heads.<n>.ups.* |
UPS mode / grid-charge / bypass (UO/UG/FP) |
heads.<n>.fault.* |
fault bitmasks (TF/EF/DF1/DF2/AF1/AF2/BF) — only populated while a fault is active |
heads.<n>.control.* |
all writable fields (see below) |
heads.<n>.info.* |
per-head online, lastError, rawResponse (the full raw /read) |
total.* |
combined view: capacity-weighted soc, summed batteryPower / gridPower / maxPower, onlineCount |
controller.* |
self-consumption controller telemetry (status, grid-source age) |
info.* |
connection (any head reachable) and lastUpdate |
Writable controls (heads.<n>.control.*)
By ioBroker convention all writable fields live under each head's control.*. Because that flattens their topic, this table shows what each one relates to:
| Object | Field | Relates to | Description |
|---|---|---|---|
control.GS |
GS | grid | Grid power setpoint (>0 feed-in / <0 grid charge) |
control.IS |
IS | grid | Max. grid feed-in / inverter output limit |
control.MG |
MG | grid | Max. grid-tied output power |
control.SI |
SI | battery | Min. discharge SoC (grid mode) |
control.SA |
SA | battery | Max. charge SoC (grid mode) |
control.SO |
SO | battery | Min. discharge SoC (off-grid mode) |
control.MM |
MM | mode | Local zero feed-in / self-consumption mode (coupled with MD) |
control.MD |
MD | meter | Meter connection JSON (coupled with MM) |
control.LM |
LM | mode | Local mode ( 1 blocks cloud/app control) |
control.LFB |
LFB | mode | Load priority switch |
control.LPS |
LPS | mode | Off-grid output switch |
control.PM |
PM | mode | Parallel mode |
control.TZ |
TZ | device | POSIX timezone |
control.RT |
RT | device | Restart device (button — a soft restart, not a full power-cycle) |
Tip: in ioBroker admin you can also filter the object list by the writable flag to find all controls at once.
device.PK is derived from DevType on firmware that no longer reports PK. Reserved fields (PT, SI1, SA1) are exposed read-only. Fields the manufacturer dropped (PD, UP) or that are doc-only artefacts (WT, BN) are not exposed; anything unmapped is still available in heads.<n>.info.rawResponse.
Manual meter / mode fields (MM / MD)
MM/MD are a head's own meter-based self-consumption. When you select a Control mode, the adapter manages them for you (Mode A sets MM=1 + MD on the single head; Mode B forces MM=0 on every head), and its guard re-asserts the mode-appropriate MM on the next poll — so any manual change in a control mode is temporary.
The raw fields stay writable for expert/manual use (e.g. in Off mode). They follow the official coupling: turning MM off also clears MD, and writing MD enables MM (non-empty) or disables it (empty). The MD JSON formats for the four supported meters are in the device's local API reference; in Device self-regulation mode the adapter builds them for you from the meter type and SN/IP.
Limitations
- Up to three heads per instance. Single-head operation is validated on real hardware; the multi-head split is covered by unit tests but, at the time of writing, untested on a real 2–3 head installation — feedback from multi-head setups is very welcome. Device self-regulation is single-head only.
- Heads must be on different phases (operator's responsibility). The adapter regulates the net summed grid power, not per phase.
- Per-pack balancing is handled by each head's own BMS — the adapter steers the head's overall power only and reads
battery.SC(total) for control; it does not manage individual packs. - Daily energy counters (
GD1/GD2/LD) are raw Wh, not kWh. MDandTZtake effect immediately but are not guaranteed to be echoed back verbatim by the device — confirm by effect, not by echo.- PV inputs are untested with hardware (the reference installation runs without PV modules, so
PV1–4are always 0). The integration and controller are PV-agnostic and complete, but PV firmware edge cases (e.g. battery full + PV surplus, UPS/bypass fieldsFP/UG) are unverified — feedback welcome.
Troubleshooting
info.connectionstaysfalse/ no data: first make sure local mode (LM=1) is enabled on the device — without it the local API returns no values. Then verify thathttp://<device-ip>/readis reachable from the ioBroker host (test with a browser orcurl). Per head,heads.<n>.info.onlineandheads.<n>.info.lastErrorshow which one fails.- Nothing is being controlled: check the Control mode — Off never writes. In Adapter controller set a valid grid-power source state; in Device self-regulation set a supported meter type and SN/IP.
- Device ignores
GS/ battery does not react: a head only executes a writtenGSwhenMM=0. In Adapter controller mode the adapter enforces this; if you writeGSmanually, make sure no meter is bound (MM=0). With a meter bound (MM=1) the device self-regulates and ignoresGS. - Two controllers fight over the battery: run only one. The adapter enforces
MMfor the selected mode — disable any externalGSscript (or a device's ownMMwith a different meter) before using a control mode. - Some states stay empty (
0/""): a device only returns the fields its firmware/topology actually provides (e.g. extra packsSC2–SC5, or fault bitmasks only during a fault). The complete raw response is always available inheads.<n>.info.rawResponse. - After updating from a single-head version the tree looks wrong: the object tree was restructured to
heads.<n>.*in 0.2.0. The adapter removes obsolete objects automatically on start; if anything lingers, delete the old objects (or re-add the instance).
Changelog
0.2.0 (2026-06-30)
- (Creekhail) Multi-head support: manage up to three SunEnergyXT heads in one instance. The adapter controller now computes one grid setpoint and splits it across all online heads (equal split, gated by each head's SoC headroom, with per-head power caps and overflow redistribution). New per-head object tree
heads.<n>.*and combinedtotal.*aggregates; a "Test all heads" connectivity button; device self-regulation is restricted to a single head. The object tree was restructured — existing single-head instances should be re-created (delete the old objects / re-add the instance).
0.1.1 (2026-06-29)
- (Creekhail) Released via npm trusted publishing (provenance) and a package metadata fix.
0.1.0 (2026-06-28)
- (Creekhail) Initial release: local-API polling to states; writable control fields; two switchable control modes — an adapter-side self-consumption controller (any ioBroker meter state, feed-forward + P, with watchdog/failsafe) and device self-regulation (binds a supported meter: EcoTracker / Shelly 3EM / Shelly Pro 3EM / Tasmota); plus a monitoring-only mode, with an MM-mode guard.
License
MIT License
Copyright (c) 2026 Marcus Bortel (Creekhail)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
