Skip to content

Commit 7080a01

Browse files
Developer089claude
andcommitted
Initial release: Deye Modbus hybrid inverter integration for Home Assistant
HACS-installable local_polling integration for Deye three-phase hybrid inverters (SUN-*K-SG04LP3 / SG05LP3, incl. SUN-12K-SG05LP3). Architecture modeled on the Growatt Modbus integration; register map derived from Deye's official three-phase energy-storage Modbus protocol. - Config flow with inverter-model selection; TCP (8899) or RTU-over-TCP - YAML-driven register map (68 sensors, 41 controls) read via FC03 - Coordinator with grouped reads, signed/scale/offset/word_order decoding - sensor / number / select / switch platforms + write services - HACS metadata, hassfest + HACS CI, EN/CS translations Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 parents  commit 7080a01

26 files changed

Lines changed: 3112 additions & 0 deletions

‎.gitattributes‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
* text=auto eol=lf
2+
*.py text eol=lf
3+
*.json text eol=lf
4+
*.yaml text eol=lf
5+
*.yml text eol=lf
6+
*.md text eol=lf

‎.github/workflows/release.yml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
release-zip:
12+
name: Build and attach release asset
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Create ZIP archive
19+
run: |
20+
cd custom_components
21+
zip -r deye_modbus.zip deye_modbus
22+
23+
- name: Attach ZIP to release
24+
uses: softprops/action-gh-release@v2
25+
with:
26+
files: custom_components/deye_modbus.zip

‎.github/workflows/validate.yml‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Validate
2+
3+
on:
4+
push:
5+
pull_request:
6+
schedule:
7+
- cron: "0 0 * * 0"
8+
workflow_dispatch:
9+
10+
jobs:
11+
hassfest:
12+
name: Hassfest
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Run hassfest
19+
uses: home-assistant/actions/hassfest@master
20+
21+
hacs:
22+
name: HACS
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- name: Run HACS validation
29+
uses: hacs/action@main
30+
with:
31+
category: integration

‎.gitignore‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.egg-info/
6+
.eggs/
7+
build/
8+
dist/
9+
.venv/
10+
venv/
11+
env/
12+
.pytest_cache/
13+
.mypy_cache/
14+
.ruff_cache/
15+
.coverage
16+
htmlcov/
17+
18+
# OS junk
19+
.DS_Store
20+
Thumbs.db
21+
desktop.ini
22+
23+
# IDE
24+
.idea/
25+
.vscode/
26+
*.swp
27+
*.swo
28+
29+
# Local test artifacts
30+
*.log
31+
.cache/
32+
tmp/

‎AGENTS.md‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Agents used to build this integration
2+
3+
This integration was built with the help of several AI sub-agents, each given a
4+
narrow, well-scoped job. This file documents who did what, so the work is
5+
traceable and reproducible.
6+
7+
## Orchestration
8+
9+
The main agent (Claude, Opus 4.8) did the architecture and all the coupled,
10+
correctness-critical work directly:
11+
12+
- Reverse-engineered the sample **Growatt Modbus** Home Assistant integration
13+
(`E:\Projekty\Growatt_Modbus_MID-MOD`) to reuse its YAML-map-driven,
14+
coordinator-based architecture.
15+
- Extracted the **Deye three-phase hybrid Modbus protocol** from the supplied
16+
Word document (`Modbus amit posun.docx`) into text and identified the register
17+
layout (device type `0x0500`, FC03 for all live values, realtime block
18+
500–683, settings 60–499).
19+
- Wrote the Python package: `coordinator.py` (poll-all-holding, `offset` +
20+
per-register `word_order` decoding), `config_flow.py` (with inverter-model
21+
dropdown), `__init__.py`, `mapping.py`, `models.py`, `const.py`, and the four
22+
entity platforms (`sensor`, `number`, `select`, `switch`).
23+
- Hand-authored the register map `maps/sun_3ph_hybrid.yaml` and validated it
24+
with a standalone decode harness.
25+
26+
## Sub-agents (run in parallel, in the background)
27+
28+
| # | Agent (type) | Job | Output |
29+
|---|--------------|-----|--------|
30+
| 1 | Register-map verifier (`general-purpose`) | Audited `maps/sun_3ph_hybrid.yaml` line-by-line against the extracted Deye protocol doc: addresses, scales, `signed`/S16, 32-bit `word_order`, temperature `offset`; and listed notable missing realtime registers. **Read-only** — reported findings only. | Findings folded back into the map by the main agent. |
31+
| 2 | Docs writer (`general-purpose`) | Wrote `README.md` (English + a Czech section) and `info.md` (HACS card) from the actual code. | `README.md`, `info.md` |
32+
| 3 | CI / metadata (`general-purpose`) | Created `.gitignore`, `LICENSE` (MIT), and GitHub Actions workflows `.github/workflows/validate.yml` (hassfest + HACS validation) and `release.yml` (zip + attach on release). | `.gitignore`, `LICENSE`, `.github/workflows/*` |
33+
34+
## Why this split
35+
36+
The coordinator, config flow, and register map are tightly coupled and
37+
correctness-sensitive (a wrong scale or word order silently produces bad data),
38+
so the main agent kept those. The verifier, docs, and CI/metadata jobs are
39+
independent and parallelizable, which is where sub-agents add the most value
40+
without risking conflicting edits to the same files.

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Developer089
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md‎

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# Deye Modbus for Home Assistant
2+
3+
Local Home Assistant integration for **Deye three-phase hybrid inverters** (SUN-\*K-SG04LP3 / SG05LP3 family, including the SUN-12K-SG05LP3). It talks Modbus TCP directly to the inverter's WiFi/LAN logger or an RS485-to-TCP gateway — no cloud, no SolarMAN account required.
4+
5+
[![HACS Custom](https://img.shields.io/badge/HACS-Custom-41BDF5.svg)](https://hacs.xyz/)
6+
[![Integration](https://img.shields.io/badge/type-local__polling-brightgreen.svg)](#)
7+
8+
> This is a **custom repository** for HACS. It is not (yet) in the default HACS store, so you add it manually — see [Installation](#installation).
9+
10+
---
11+
12+
## Features
13+
14+
- 100% **local polling** over Modbus TCP — nothing leaves your network.
15+
- Talks directly to the Deye WiFi/LAN logger (default port **8899**) or to an RS485↔TCP gateway (Elfin EW11, USR, etc. — usually port **502**).
16+
- Guided **config flow**: pick your inverter model from a dropdown, then enter host, port, Modbus unit ID and scan interval. No YAML editing needed.
17+
- Rich set of **sensors**: PV strings, battery, grid import/export, per-phase grid/inverter/load, temperatures, plus daily and lifetime energy counters (ready for the HA Energy dashboard).
18+
- Writable **controls** as native HA entities: work mode, solar sell, grid/generator charge, battery current & SOC limits, max sell power, and full 6-slot time-of-use programming.
19+
- Driven by a human-readable **YAML register map** — adding a model is just a new map file, no code changes.
20+
- **Options flow** to tune scan interval, transport, address offset and serial parameters at any time.
21+
- Low-level **services** for advanced/manual register access.
22+
- `pymodbus` is pulled in automatically by Home Assistant via the manifest.
23+
24+
---
25+
26+
## Installation
27+
28+
### Via HACS (recommended)
29+
30+
1. In Home Assistant go to **HACS**.
31+
2. Open the top-right menu **⋮ → Custom repositories**.
32+
3. Add the repository URL `https://github.com/Developer089/deye-modbus-ha` and choose category **Integration**.
33+
4. Find **Deye Modbus (Hybrid Inverter)** in the list and click **Download / Install**.
34+
5. **Restart Home Assistant.**
35+
6. Go to **Settings ▸ Devices & Services ▸ Add Integration** and search for **Deye Modbus**.
36+
37+
### Manual installation
38+
39+
1. Copy the folder `custom_components/deye_modbus` from this repository into your Home Assistant `/config/custom_components/` directory, so you end up with `/config/custom_components/deye_modbus/`.
40+
2. **Restart Home Assistant.**
41+
3. Add the integration via **Settings ▸ Devices & Services ▸ Add Integration → "Deye Modbus"**.
42+
43+
---
44+
45+
## Configuration
46+
47+
When you add the integration you get a single setup form:
48+
49+
| Field | Default | Notes |
50+
|-------|---------|-------|
51+
| **Inverter model** | SUN-12K-SG05LP3 | Dropdown; selects the bundled register map. |
52+
| **Host / IP** | — | IP address of the inverter's logger or your RS485↔TCP gateway, e.g. `192.168.x.x`. |
53+
| **Port** | `8899` | See the port guidance below. |
54+
| **Modbus unit ID** | `1` | The Modbus slave/device address. Leave at `1` unless you changed it on a gateway. |
55+
| **Scan interval (s)** | `15` | How often to poll, range **5–300** seconds. |
56+
57+
### Which port?
58+
59+
- **`8899`** — the Deye/SolarMAN **WiFi or LAN stick logger** exposes Modbus TCP on this port. This is the right choice for most people plugging into the inverter's own logger.
60+
- **`502`** — a third-party **RS485-to-TCP gateway** (Elfin EW11, USR, etc.) wired to the inverter's Modbus/BMS RS485 port. These typically speak standard Modbus TCP on 502.
61+
62+
If you are unsure, try `8899` first; if no data appears, try `502`.
63+
64+
### Finding the inverter's IP
65+
66+
Look in your router's DHCP client list for the logger (often named `Solarman*` / `IGEN*` / the stick's serial), or use the SolarMAN app / a network scanner. Assigning it a static DHCP lease is recommended so the address never changes.
67+
68+
---
69+
70+
## Supported models
71+
72+
All of these share the three-phase low-voltage hybrid protocol (device type `0x0500`) and the same register map:
73+
74+
| Model key | Label |
75+
|-----------|-------|
76+
| `sun12k_sg05lp3` | Deye SUN-12K-SG05LP3 (3-phase hybrid) — default |
77+
| `sun_sg05lp3_3ph` | Deye SUN-5/6/8/10/12K-SG05LP3 (3-phase hybrid) |
78+
| `sun_sg04lp3_3ph` | Deye SUN-5/6/8/10/12K-SG04LP3 (3-phase hybrid) |
79+
80+
Rebadged units on the same platform (Sunsynk, etc.) will generally work too.
81+
82+
---
83+
84+
## Entities overview
85+
86+
### Sensors (selection)
87+
88+
| Area | Entities |
89+
|------|----------|
90+
| Status | Run State |
91+
| PV | PV1/PV2 voltage, current, power (PV3/PV4 available, disabled by default) |
92+
| Battery | SOC, voltage, current, power, temperature (corrected capacity disabled by default) |
93+
| Grid / CT | Grid voltage L1–L3, frequency, per-phase power, total grid power (import +, export −) |
94+
| Inverter | Inverter total power (per-phase voltages, frequency disabled by default) |
95+
| Load | Total load power (per-phase load power/voltage disabled by default) |
96+
| Backup / Generator | Backup power, generator voltage/power (disabled by default) |
97+
| Temperatures | AC (radiator) temperature, DC temperature |
98+
| Energy — today | PV production, battery charge/discharge, grid import/export, load consumption |
99+
| Energy — total | PV production, battery charge/discharge, grid import/export, load consumption (32-bit lifetime counters) |
100+
101+
### Controls
102+
103+
| Type | Entities |
104+
|------|----------|
105+
| Switch | Inverter On/Off, Solar Sell (Export), Grid Charge Enable, Generator Charge Enable |
106+
| Select | Work Mode (Selling First / Zero Export To Load / Zero Export To CT) |
107+
| Number | Max Sell Power, Max Grid Output Power, Active Power Regulation, Battery Max Charge/Discharge Current, Grid Charge Current, Battery Shutdown/Restart/Low SOC, Battery Capacity, Grid Voltage High/Low limits |
108+
| Time-of-use | 6 slots × Time / Power / SOC / Charge Source (Off / Grid / Generator / Grid+Generator) |
109+
110+
> **Disabled-by-default entities.** To keep the device tidy, some entities ship disabled: PV3/PV4, per-phase inverter/load detail, generator/backup, grid protection limits, and all time-of-use slots. Enable any of them under the device's **Entities** list → open the entity → **Settings** → toggle *Enabled*.
111+
112+
---
113+
114+
## Options
115+
116+
Open the integration and click **Configure** to change (no restart needed — the entry reloads):
117+
118+
- **Scan interval** — 5–300 s.
119+
- **Transport** — `tcp` (standard Modbus TCP) or `rtutcp` (RTU frame over a raw TCP socket, for some gateways).
120+
- **Address offset** — added to every register address, for gateways that shift the map.
121+
- **Serial parameters** — baud rate, byte size, parity (N/E/O), stop bits (only relevant for `rtutcp`).
122+
123+
---
124+
125+
## Services
126+
127+
For advanced/manual register access. Addresses are decimal and given **before** any configured address offset.
128+
129+
| Service | Purpose | Key fields |
130+
|---------|---------|-----------|
131+
| `deye_modbus.write_register` | Write one holding register (FC06). | `address`, `value` (0–65535) |
132+
| `deye_modbus.write_registers` | Write a list of 16-bit values starting at an address (FC16). | `address`, `values` (list) |
133+
| `deye_modbus.write_u32` | Write a 32-bit value across two registers (FC16). | `address`, `value` (0–4294967295), `word_order` (`high_low` default / `low_high`) |
134+
135+
Example:
136+
137+
```yaml
138+
service: deye_modbus.write_register
139+
data:
140+
address: 145 # Solar Sell enable
141+
value: 1
142+
```
143+
144+
---
145+
146+
## How it works / Modbus notes
147+
148+
- **Everything is read with function code `0x03` (FC03, read holding registers)** — on this inverter both the live measurements and the writable settings live in the holding-register space. Writes use FC06 (single) / FC16 (multiple).
149+
- **32-bit energy counters are stored low-word-first** (`word_order: low_high`, little-endian by word). The integration reassembles them automatically.
150+
- **Temperatures** use a raw offset of 1000 and scale 0.1, i.e. `°C = (raw − 1000) × 0.1`.
151+
- **Signed values** (battery/grid/load power and current) are decoded as two's-complement. Grid total power is **positive when importing, negative when exporting**.
152+
- The register map is a plain YAML file (`custom_components/deye_modbus/maps/sun_3ph_hybrid.yaml`) derived from Deye's official three-phase energy-storage Modbus protocol document.
153+
154+
---
155+
156+
## Troubleshooting
157+
158+
- **No data / entities unavailable.** Double-check the **port** (`8899` for the Deye logger vs `502` for an RS485↔TCP gateway) and the **Modbus unit ID** (usually `1`). Confirm the IP is reachable from the HA host (`ping`), and that the logger firmware is recent.
159+
- **Only one Modbus master at a time.** The inverter/logger accepts a **single** Modbus connection. This integration will **conflict with the SolarMAN cloud logging and with any other Modbus poller** (a second HA integration, Node-RED, etc.). If the SolarMAN app / cloud is actively connected you may see dropouts — expect to give up cloud logging, or poll via a separate RS485 gateway.
160+
- **Intermittent timeouts.** Increase the **scan interval**, reduce competing connections, or improve WiFi signal to the logger. For flaky gateways try the `rtutcp` transport in Options.
161+
- **Wrong or shifted values.** If a gateway shifts the address map, set an **address offset** in Options.
162+
163+
---
164+
165+
## Disclaimer
166+
167+
The control and service entities **write settings to your inverter**. Changing work mode, sell/charge behaviour, SOC and current limits, grid protection windows or time-of-use programming **can affect how your inverter operates**, including battery health and grid interaction. Use these features at your own risk; the authors accept no liability for any damage or loss. If in doubt, leave the write entities disabled and use the integration for monitoring only. This project is not affiliated with or endorsed by Deye.
168+
169+
---
170+
171+
## Credits
172+
173+
- Architecture modeled on a **Growatt Modbus** Home Assistant integration (coordinator + YAML-driven register map pattern).
174+
- Register map derived from **Deye's official Modbus protocol documentation** for the three-phase energy-storage (hybrid) inverters.
175+
- Built on [`pymodbus`](https://github.com/pymodbus-dev/pymodbus).
176+
177+
---
178+
179+
## Česky
180+
181+
**Deye Modbus pro Home Assistant** je lokální integrace pro **třífázové hybridní měniče Deye** (řada SUN-\*K-SG04LP3 / SG05LP3, včetně SUN-12K-SG05LP3). Komunikuje přímo přes Modbus TCP s WiFi/LAN loggerem měniče (výchozí port **8899**) nebo s převodníkem RS485↔TCP (obvykle port **502**). Nepotřebuje cloud ani účet SolarMAN — vše probíhá ve vaší síti.
182+
183+
### Instalace přes HACS
184+
185+
1. V **HACS** otevřete menu **⋮ → Custom repositories** (Vlastní repozitáře).
186+
2. Přidejte adresu `https://github.com/Developer089/deye-modbus-ha` a jako kategorii zvolte **Integration**.
187+
3. Najděte **Deye Modbus (Hybrid Inverter)** a nainstalujte.
188+
4. **Restartujte Home Assistant.**
189+
5. Přejděte do **Nastavení ▸ Zařízení a služby ▸ Přidat integraci** a vyhledejte **Deye Modbus**.
190+
191+
Ruční instalace: zkopírujte složku `custom_components/deye_modbus` do `/config/custom_components/` a Home Assistant restartujte.
192+
193+
### Konfigurace
194+
195+
Ve formuláři při přidání integrace zadáte:
196+
197+
- **Model měniče** — výběr z rozbalovacího seznamu (určuje mapu registrů).
198+
- **Host / IP** — adresa loggeru nebo převodníku, např. `192.168.x.x`.
199+
- **Port** — `8899` pro WiFi/LAN logger Deye, `502` pro převodník RS485↔TCP. Pokud si nejste jistí, zkuste nejdřív `8899`.
200+
- **Modbus unit ID** — obvykle `1`.
201+
- **Interval dotazování** — `15` s (rozsah 5–300 s).
202+
203+
IP adresu měniče najdete v seznamu klientů DHCP na routeru; doporučuje se nastavit statickou (rezervovanou) adresu.
204+
205+
### Entity a ovládání
206+
207+
Integrace zpřístupní senzory (FV panely, baterie, síť import/export, zátěž, teploty, denní i celková energie) a ovládací prvky (režim práce, prodej do sítě, nabíjení ze sítě/generátoru, limity proudu a SOC baterie, maximální prodejní výkon, programování podle času – TOU). Některé entity jsou ve výchozím stavu **vypnuté** (PV3/PV4, detaily po fázích, TOU sloty) — zapnete je v nastavení dané entity.
208+
209+
### Upozornění
210+
211+
Zápisové entity a služby **mění nastavení měniče** a mohou ovlivnit jeho chování i baterii. Používejte na vlastní riziko. Pozor: měnič/logger přijímá **jen jedno Modbus spojení** — integrace se proto vylučuje se SolarMAN cloudem i s jiným Modbus dotazovačem.

0 commit comments

Comments
 (0)