Skip to content

Commit 7fd5f5f

Browse files
authored
feat: add CHINT DTSU666 meter profile (#2)
* Add DTSU666 profile and rename meter bridge component * Harden meter profiles and compatibility - add a shared profile codec and golden-vector protocol tests - preserve the legacy component domain with explicit deprecation rules - harden Modbus, WebSocket, authentication, and configuration handling - expand CI coverage and fork release documentation * Update GitHub Actions runtimes Use the current checkout and Python setup action generations to avoid deprecated Node.js runtime warnings. * Prepare DTSU666 changes for upstream review Replace fork-specific repository references with upstream URLs, preserve upstream component ownership metadata, move release notes to Unreleased, and document the observed Deye CHNT field exchange without claiming physical DTSU666 validation. * Fix DTSU666 scales and add reactive power telemetry * Set component version to 0.2.1 * Add OpenDTU energy and inverter telemetry sensors * Resolve upstream Modbus API conflict
1 parent 1e0a7af commit 7fd5f5f

26 files changed

Lines changed: 2857 additions & 978 deletions

‎.github/ISSUE_TEMPLATE/issue.yml‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
name: Report an issue
2-
description: Report a problem with the OpenDTU to SDM630 ESPHome component
2+
description: Report a problem with the OpenDTU Meter Bridge ESPHome component
33
body:
44
- type: markdown
55
attributes:
66
value: |
77
Before reporting an issue, please review the [README](https://github.com/Lewa-Reka/esphome-opendtu-to-sdm630/blob/main/README.md) - especially **Requirements**, **Configuration reference**, and **Failsafe behaviour**.
88
9-
**Scope of this repository:** the `opendtu_sdm630` ESPHome component only (WebSocket livedata → Modbus SDM630 emulator).
9+
**Scope of this repository:** the `opendtu_meter_bridge` ESPHome component only (WebSocket livedata → selectable SDM630/DTSU666 Modbus profile).
1010
1111
**Out of scope - issues will be closed without a response** if the report does not show that the problem is in this component, for example:
1212
- OpenDTU setup, DTU hardware, or Hoymiles microinverter connectivity
13-
- Hybrid inverter wiring, RS485 port setup, or inverter menu configuration (e.g. Deye AC Couple, Grid Tie Meter 2, Eastron meter type)
13+
- Hybrid inverter wiring, RS485 port setup, or inverter menu configuration (e.g. Deye AC Couple, Grid Tie Meter 2, Eastron/CHNT meter selection)
1414
15-
You must demonstrate a component-side fault: ESPHome logs (`opendtu_sdm630`), published sensors (WebSocket Status, Data Valid, phase values), or incorrect Modbus register output from the bridge - not only symptoms on the inverter display.
15+
You must demonstrate a component-side fault: ESPHome logs (`opendtu_meter_bridge`), published sensors (WebSocket Status, Data Valid, phase values), or incorrect Modbus register output from the bridge - not only symptoms on the inverter display.
1616
1717
- type: textarea
1818
id: problem
@@ -47,7 +47,18 @@ body:
4747
label: Component version
4848
description: >
4949
Value from the **Component Version** text sensor, a git tag/commit.
50-
placeholder: e.g. 0.0.1
50+
placeholder: e.g. 0.2.0
51+
validations:
52+
required: true
53+
54+
- type: dropdown
55+
id: meter_profile
56+
attributes:
57+
label: Meter profile
58+
description: Select the value configured under `opendtu_meter_bridge.meter_profile`.
59+
options:
60+
- sdm630 (Eastron SDM630)
61+
- dtsu666 (CHINT DTSU666 / Deye CHNT)
5162
validations:
5263
required: true
5364

@@ -91,13 +102,15 @@ body:
91102
attributes:
92103
label: Relevant YAML (sanitized)
93104
description: >
94-
Paste the `opendtu_sdm630:`, `uart:`, and `modbus:` blocks from your config.
105+
Paste the `opendtu_meter_bridge:`, `uart:`, and `modbus:` blocks from your config.
95106
Remove passwords and WiFi credentials - use `!secret` placeholders.
96107
render: yaml
97108
placeholder: |
98-
opendtu_sdm630:
109+
opendtu_meter_bridge:
99110
host: 192.168.1.50
100111
password: !secret opendtu_password
112+
# Allowed values: sdm630 or dtsu666.
113+
meter_profile: sdm630
101114
slave_address: 0x02
102115
microinverter_map:
103116
- name: Garage-HMS-2000-4T
@@ -110,11 +123,11 @@ body:
110123
description: |
111124
**Required for most reports.** Output from `esphome logs <your-config>.yaml`.
112125
113-
Set `logger: level: DEBUG` temporarily if needed. Include lines tagged `opendtu_sdm630`.
126+
Set `logger: level: DEBUG` temporarily if needed. Include lines tagged `opendtu_meter_bridge`.
114127
render: txt
115128
placeholder: |
116-
[00:00:00][I][opendtu_sdm630:379]: WebSocket connected to OpenDTU
117-
[00:00:00][W][opendtu_sdm630:258]: Microinverter serial '...' not found in livedata
129+
[00:00:00][I][opendtu_meter_bridge]: WebSocket connected to OpenDTU
130+
[00:00:00][W][opendtu_meter_bridge]: Microinverter serial '...' not found in livedata
118131
validations:
119132
required: true
120133

‎.github/workflows/build-ci.yaml‎

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,102 @@ concurrency:
1313
cancel-in-progress: true
1414

1515
jobs:
16+
protocol-tests:
17+
name: Meter profile protocol tests
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout source code
21+
uses: actions/checkout@v7
22+
23+
- name: Build meter profile tests
24+
run: >-
25+
c++ -std=c++17 -Wall -Wextra -Werror -pedantic
26+
-fsanitize=address,undefined -fno-omit-frame-pointer -I.
27+
tests/meter_profile_test.cpp
28+
components/opendtu_meter_bridge/meter_profile.cpp
29+
components/opendtu_meter_bridge/meter_profile_codec.cpp
30+
components/opendtu_meter_bridge/meter_profile_sdm630.cpp
31+
components/opendtu_meter_bridge/meter_profile_dtsu666.cpp
32+
-o "${RUNNER_TEMP}/meter-profile-tests"
33+
34+
- name: Run meter profile tests
35+
run: "${RUNNER_TEMP}/meter-profile-tests"
36+
37+
configuration-tests:
38+
name: Configuration validation / ${{ matrix.esphome-version }}
39+
runs-on: ubuntu-latest
40+
strategy:
41+
fail-fast: false
42+
matrix:
43+
esphome-version:
44+
- stable
45+
- 2026.7.3
46+
- 2025.6.3
47+
steps:
48+
- name: Checkout source code
49+
uses: actions/checkout@v7
50+
51+
- name: Set up Python
52+
uses: actions/setup-python@v7
53+
with:
54+
python-version: "3.12"
55+
56+
- name: Install ESPHome ${{ matrix.esphome-version }}
57+
env:
58+
ESPHOME_VERSION: ${{ matrix.esphome-version }}
59+
run: |
60+
if [ "${ESPHOME_VERSION}" = "stable" ]; then
61+
python -m pip install esphome
62+
else
63+
python -m pip install "esphome==${ESPHOME_VERSION}"
64+
fi
65+
66+
- name: Create secrets.yaml
67+
run: cp secrets.yaml.example tests/secrets.yaml
68+
69+
- name: Validate the default profile
70+
run: esphome -q config tests/meter_bridge_default_ci.yaml >/dev/null
71+
72+
- name: Validate the deprecated meter_type option
73+
run: esphome -q config tests/meter_bridge_legacy_option_ci.yaml >/dev/null
74+
75+
- name: Reject conflicting profile selectors
76+
run: |
77+
if esphome -q config tests/meter_bridge_conflicting_options_invalid.yaml >/dev/null; then
78+
echo "Expected conflicting meter selectors to fail validation" >&2
79+
exit 1
80+
fi
81+
82+
- name: Reject conflicting component domains
83+
run: |
84+
if esphome -q config tests/meter_bridge_conflicting_domains_invalid.yaml >/dev/null; then
85+
echo "Expected the neutral and legacy component domains to conflict" >&2
86+
exit 1
87+
fi
88+
1689
build-ci:
17-
name: Building opendtu_sdm630_ci / ${{ matrix.esphome-version }}
90+
name: Building ${{ matrix.config }} / ${{ matrix.esphome-version }}
1891
runs-on: ubuntu-latest
1992
strategy:
2093
fail-fast: false
2194
matrix:
2295
esphome-version:
2396
- stable
97+
- 2026.7.3
98+
- 2025.6.3
99+
config:
100+
- meter_bridge_sdm630_ci.yaml
101+
- meter_bridge_dtsu666_ci.yaml
102+
- opendtu_sdm630_legacy_ci.yaml
24103
steps:
25104
- name: Checkout source code
26-
uses: actions/checkout@v4
105+
uses: actions/checkout@v7
27106

28107
- name: Create secrets.yaml
29108
run: cp secrets.yaml.example tests/secrets.yaml
30109

31110
- name: ESPHome ${{ matrix.esphome-version }}
32111
uses: esphome/build-action@v7
33112
with:
34-
yaml-file: tests/opendtu_sdm630_ci.yaml
113+
yaml-file: tests/${{ matrix.config }}
35114
version: ${{ matrix.esphome-version }}

‎CHANGELOG.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented here.
4+
5+
## Unreleased
6+
7+
### Added
8+
9+
- ESPHome sensors for daily and lifetime production, summed only across microinverters selected in `microinverter_map`.
10+
- ESPHome sensors for average mapped-inverter temperature and aggregate inverter efficiency.
11+
12+
### Changed
13+
14+
- Extended OpenDTU livedata parsing to consume `INV["0"]` production, temperature, efficiency, and DC-power fields in addition to the AC channel.
15+
16+
### Added
17+
18+
- Selectable `sdm630` and `dtsu666` meter profiles through `meter_profile`.
19+
- CHINT DTSU666 instantaneous voltage, current, active-power, and frequency register mapping based on the published CHINT Modbus specification.
20+
- Separate profile descriptor tables, a shared `meter_profile_codec`, and CI build configurations for SDM630 and DTSU666.
21+
- Golden-vector protocol tests for exact register words, FP32 encoding, profile windows, and boundary handling.
22+
- A compatibility wrapper for existing `components: [opendtu_sdm630]` and `opendtu_sdm630:` configurations.
23+
- Migration, Modbus behavior, release, and profile-extension documentation.
24+
25+
### Changed
26+
27+
- Introduced `opendtu_meter_bridge` / OpenDTU Meter Bridge as the canonical ESPHome component, C++ namespace, class, file, log-tag, reference-configuration, and device-facing naming.
28+
- Raised the documented and tested minimum ESPHome version to 2025.6.3.
29+
- Added compatibility with the ESPHome Modbus server API introduced in newer releases while retaining the older supported API path.
30+
- Made DTSU666 current registers positive RMS magnitudes while retaining directional active power and the legacy SDM630 current convention.
31+
- Hardened WebSocket callback handoff with synchronized state, bounded/coalesced event queuing, and validated fragmented frames.
32+
- Removed fixed-size Basic Auth buffers, marked the password as sensitive in supported ESPHome versions, and validated Modbus slave addresses and read quantities.
33+
- Updated the GitHub-hosted checkout and Python setup actions to their current Node.js runtime generation.
34+
35+
### Deprecated
36+
37+
- The legacy `opendtu_sdm630` component/domain remains functional through a compatibility wrapper, emits a deprecation warning, and defaults to the SDM630 profile.
38+
- `meter_type` remains accepted as a deprecated alias for `meter_profile`, with the same `sdm630` and `dtsu666` values.
39+
- Both deprecated aliases remain supported throughout all 0.2.x releases and may be removed no earlier than v0.3.0.
40+
41+
### Compatibility
42+
43+
- Existing v0.0.1 configurations can use the updated component without changing `components: [opendtu_sdm630]` or the `opendtu_sdm630:` domain. They receive a deprecation warning and retain SDM630 as the default profile.
44+
- New configurations should use `components: [opendtu_meter_bridge]`, the `opendtu_meter_bridge:` domain, and `meter_profile`.
45+
- The legacy and neutral component domains cannot be configured together in one ESPHome node.
46+
47+
### Validation status
48+
49+
- The SDM630 profile has been validated with the documented Deye setup.
50+
- The DTSU666 phase active-power block has been exercised with Deye configured for CHNT and Grid Tie Meter 2; all 17 captured FC03 requests to slave `0x02` received valid responses matching OpenDTU data.
51+
- The DTSU666 profile is implemented from the published specification and has not been compared with physical DTSU666 hardware.
52+
- Both neutral profiles and the legacy-domain compatibility path are compiled in CI against ESPHome stable, the pinned 2026.7.3 release, and the minimum supported ESPHome version.
53+
- Host-side golden-vector tests validate the profile codec and exact SDM630/DTSU666 register output.
54+
55+
## v0.0.1 - 2026-06-06
56+
57+
- Original upstream release by Lewa-Reka.
58+
- Added the `opendtu_sdm630` ESPHome external component for exposing OpenDTU measurements through an Eastron SDM630-compatible Modbus register map.

‎NOTICE‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
================================================================================
2-
ESPHome OpenDTU to SDM630
2+
ESPHome OpenDTU Meter Bridge
33
Copyright 2026 Lewa-Reka <lewareka.yt@gmail.com>
44

55
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@ limitations under the License.
1616
================================================================================
1717

1818
This project provides an ESPHome external component that bridges OpenDTU
19-
microinverter data to a Modbus RTU Eastron SDM630 energy meter emulator.
19+
microinverter data to selectable Modbus RTU Eastron SDM630 and CHINT DTSU666
20+
register profiles.
2021

2122
Project Repository: https://github.com/Lewa-Reka/esphome-opendtu-to-sdm630
2223

0 commit comments

Comments
 (0)