I Reverse-Engineered My Solar Inverter's API to Export 5kW to the Grid — Here's What I Found
TL;DR: Solplanet/AISWEI hybrid inverters have a hidden "Custom mode" (mod_r=4) that enables force grid export. The documented TOU mode (mod_r=5) is broken on current firmware. This took 12 hours of debugging to discover, and the fix is 3 lines of code.
Last week I installed a 46kWh battery system with a Solplanet ASW12kH-T3 hybrid inverter. The goal was simple: charge from solar during the day, export to the grid during peak pricing windows on Amber Electric, and pocket the difference.
The hardware was ready. The Amber API was feeding real-time spot prices. The automation was running every 5 minutes. Everything looked perfect — except the battery refused to export a single watt to the grid.
The Problem
Solplanet exposes a local HTTP API on the inverter's WiFi dongle (an ESP32). You can read battery state, solar production, and grid power. You can also write settings — battery work mode, charge/discharge limits, and TOU schedules.
The documentation (what little exists) says:
-
mod_r=2→ Self-consumption mode -
mod_r=5→ Time-of-use mode (with schedule)
Self-consumption worked fine — the battery would discharge to cover home load. But it would never push power to the grid. That's the difference between saving $1-2/day and earning $6-7/night.
TOU mode accepted every setting I threw at it. The API returned {"dat": "ok"} for both setbattery and setdefine (the schedule endpoint). The schedule was correctly readable via getdefine.cgi. But the battery sat at 0W, stubbornly refusing to discharge.
What I Tried (and Failed)
Over 12 hours, I:
Decoded the TOU schedule encoding — reverse-engineered the slot format:
(hour << 24) | (half_hour << 17) | (duration << 14) | discharge_bit. Slots were being written correctly.Cycled through every mode byte — tried mode values 0-5 in the schedule slots. None triggered discharge.
Tested self-consumption — confirmed it discharges to cover home load (1499W), but never exports surplus.
Scanned Modbus registers — the ESP32 has a
fdbg.cgiendpoint for raw Modbus RTU frames. Device 4 (battery) returned "Illegal Function" on all holding and input registers. Dead end.Checked the Solplanet cloud API — read-only. No write endpoints at all.
Nearly crashed the ESP32 — hammered it with too many API calls and it stopped responding for 10 minutes. Lesson: the dongle has very limited concurrent connection capacity.
The Breakthrough
At 9:30 PM, frustrated and running out of ideas, I found a small GitHub repository: amber-solplanet — "Optimise battery charge/discharge for Solplanet on Amber Electric."
Someone had already solved this exact problem. The answer was hiding in plain sight:
SELF_CONSUMPTION_MODE = 2
CUSTOM_MODE = 4 # ← THIS IS THE KEY
Custom mode (mod_r=4), not TOU mode (mod_r=5).
The working sequence:
- Write a discharge schedule slot via
setdefine(the same API that TOU uses) - Set
mod_r=4viasetbattery - Watch the battery ramp from 0W → 1939W → 5045W in 30 seconds
The documentation never mentions mod_r=4 for this purpose. The HA Solplanet integration lists it as "Custom mode" but doesn't explain what it does. The Solplanet app doesn't expose it. It's essentially an undocumented forced-dispatch mode.
The Safety Trick
The amber-solplanet project uses a clever pattern: backdated schedule slots.
Instead of writing a slot for the current time (which might miss the start window), you write a slot that started 30 minutes ago with a 1-hour duration. This means:
- The slot is always "active" when written
- It naturally expires in ~30 minutes if the automation fails
- Stale commands don't persist — the inverter falls back to self-consumption
This is critical for safety. If your automation crashes at 2 AM, you don't want the battery to keep exporting until it's flat.
The Numbers
| Metric | Self-consumption only | With Custom mode export |
|---|---|---|
| Battery discharge | 400-800W (home load) | 5045W (full power) |
| Grid export | 0 kWh | ~40 kWh/night |
| Daily revenue | $1-2 (savings) | $6-7 (export earnings) |
| Annual value | ~$500 | ~$2,000-2,500 |
What You Need
If you have a Solplanet/AISWEI hybrid inverter with battery and Amber Electric (or any spot-price retailer):
- Find your inverter's local IP (check your router's DHCP table)
- API endpoints:
getdevdata.cgi,getdev.cgi,setting.cgi,getdefine.cgi - Use
mod_r=4(Custom mode) for force discharge - Use
mod_r=2(Self-consumption) as your safe fallback - Write short-lived schedule slots that auto-expire
-
Do NOT use
mod_r=5(TOU mode) — it's broken on current firmware
The full automation code is open source: ha-smartshift
Lessons Learned
- Documentation lies. The API docs say TOU mode supports scheduled discharge. It doesn't — on this firmware, at least.
- Look for prior art. Someone else had this exact problem and solved it months ago. A GitHub search saved me from the Modbus rabbit hole.
- ESP32 dongles are fragile. One request every 5 seconds max. Don't scan Modbus registers in a tight loop or you'll brick the dongle for 10 minutes.
- Backdated slots are genius. They solve the "stale command" problem elegantly — no cleanup needed, they just expire.
- Self-consumption mode is your friend when you're debugging. It always works and never does anything dangerous.
If you're fighting the same battle with a Solplanet inverter, I hope this saves you 12 hours. The code is all open source — PRs welcome.
Top comments (0)