From b71ea9fcfcf96fb9448c13802c54cb1c59432ec1 Mon Sep 17 00:00:00 2001 From: Jerome Douven Date: Fri, 3 Jul 2026 18:09:34 +1000 Subject: [PATCH 1/3] fix(1P): scale AC power registers by register 54 (AC power ratio) Per the V119 protocol, the AC power registers 167-169 (grid), 170-172 (external CT) and 176-178 (load) are reported in units of register 54 (1W or 10W per LSB). Read register 54 as an "AC Power Ratio" sensor and multiply those power sensors by it, so values match the inverter display (e.g. External CT Power 875 -> 8750 when the ratio is 10). Falls back to the raw value while the ratio is unread. Co-Authored-By: Claude Opus 4.8 --- pv_inverter/packages/deye_hybrid_1p/grid.yaml | 26 +++++++++++++++++++ pv_inverter/packages/deye_hybrid_1p/load.yaml | 6 +++++ 2 files changed, 32 insertions(+) diff --git a/pv_inverter/packages/deye_hybrid_1p/grid.yaml b/pv_inverter/packages/deye_hybrid_1p/grid.yaml index 2af6a72..3d24ac4 100644 --- a/pv_inverter/packages/deye_hybrid_1p/grid.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/grid.yaml @@ -21,11 +21,27 @@ globals: restore_value: yes sensor: + # Register 54 = "AC power ratio" (1 or 10). Per the V119 protocol, the AC power + # registers 167-169, 170-172 and 176-178 are reported in units of this value (1W + # or 10W per LSB). Read it once and multiply those power sensors by it. + - platform: modbus_controller + modbus_controller_id: ${modbus_controller_id} + name: "AC Power Ratio" + id: ac_power_ratio + register_type: holding + address: 54 + value_type: U_WORD + accuracy_decimals: 0 + entity_category: diagnostic + icon: "mdi:multiplication" + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "Grid L1 Power" register_type: holding address: 167 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -38,6 +54,8 @@ sensor: name: "Grid L2 Power" register_type: holding address: 168 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -50,6 +68,8 @@ sensor: name: "Grid Power" register_type: holding address: 169 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -208,6 +228,8 @@ sensor: name: "External CT L1 Power" register_type: holding address: 170 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power accuracy_decimals: 0 @@ -219,6 +241,8 @@ sensor: name: "External CT L2 Power" register_type: holding address: 171 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power accuracy_decimals: 0 @@ -230,6 +254,8 @@ sensor: name: "External CT Power" register_type: holding address: 172 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power accuracy_decimals: 0 diff --git a/pv_inverter/packages/deye_hybrid_1p/load.yaml b/pv_inverter/packages/deye_hybrid_1p/load.yaml index ef27d9c..214bc2e 100644 --- a/pv_inverter/packages/deye_hybrid_1p/load.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/load.yaml @@ -43,6 +43,8 @@ sensor: name: "Load L1 Power" register_type: holding address: 176 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -55,6 +57,8 @@ sensor: name: "Load L2 Power" register_type: holding address: 177 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -67,6 +71,8 @@ sensor: name: "Load Power" register_type: holding address: 178 + filters: + - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' unit_of_measurement: "W" device_class: power state_class: "measurement" From 15099109ff581550be27c46ad133deb5a53124ac Mon Sep 17 00:00:00 2001 From: Jerome Douven Date: Sat, 11 Jul 2026 11:11:19 +1000 Subject: [PATCH 2/3] refactor(1P): only scale AC power on known ratio, hoist lambda into substitution Per PR #123 review: guard the register 54 multiply so it only applies on a verified 10W/LSB value and passes raw watts through otherwise. Confirmed on hardware: SG02 10kW reports ratio 10 (10W units), SG04 6kW reports 0 (1W units). NaN == 10.0f is false, so the not-yet-read state needs no isnan check. Lambda hoisted into a substitution following the tou.yaml pattern. Co-Authored-By: Claude Fable 5 --- pv_inverter/packages/deye_hybrid_1p/grid.yaml | 25 ++++++++++++------- pv_inverter/packages/deye_hybrid_1p/load.yaml | 13 +++++++--- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/pv_inverter/packages/deye_hybrid_1p/grid.yaml b/pv_inverter/packages/deye_hybrid_1p/grid.yaml index 3d24ac4..7ff166c 100644 --- a/pv_inverter/packages/deye_hybrid_1p/grid.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/grid.yaml @@ -12,6 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +substitutions: + # Register 54 = "AC power ratio". Only scale when it reads a known 10W/LSB + # value; pass raw watts through otherwise (covers 1, 0/unsupported and the + # not-yet-read NaN state). + func_scale_ac_power: "return (id(ac_power_ratio).state == 10.0f) ? x * 10.0f : x;" + globals: - id: last_total_energy_bought type: float @@ -21,9 +27,10 @@ globals: restore_value: yes sensor: - # Register 54 = "AC power ratio" (1 or 10). Per the V119 protocol, the AC power - # registers 167-169, 170-172 and 176-178 are reported in units of this value (1W - # or 10W per LSB). Read it once and multiply those power sensors by it. + # Register 54 = "AC power ratio". Per the V119 protocol, the AC power registers + # 167-169, 170-172 and 176-178 are reported in units of this value (1W or 10W + # per LSB). Verified on hardware: SG02 10kW reads 10 (10W units), SG04 6kW + # reads 0 (1W units) - so only a value of 10 triggers scaling. - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "AC Power Ratio" @@ -41,7 +48,7 @@ sensor: register_type: holding address: 167 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -55,7 +62,7 @@ sensor: register_type: holding address: 168 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -69,7 +76,7 @@ sensor: register_type: holding address: 169 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -229,7 +236,7 @@ sensor: register_type: holding address: 170 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power accuracy_decimals: 0 @@ -242,7 +249,7 @@ sensor: register_type: holding address: 171 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power accuracy_decimals: 0 @@ -255,7 +262,7 @@ sensor: register_type: holding address: 172 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power accuracy_decimals: 0 diff --git a/pv_inverter/packages/deye_hybrid_1p/load.yaml b/pv_inverter/packages/deye_hybrid_1p/load.yaml index 214bc2e..ec04bbe 100644 --- a/pv_inverter/packages/deye_hybrid_1p/load.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/load.yaml @@ -11,6 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +substitutions: + # Register 54 = "AC power ratio" (defined in grid.yaml). Only scale when it + # reads a known 10W/LSB value; pass raw watts through otherwise (covers 1, + # 0/unsupported and the not-yet-read NaN state). + func_scale_ac_power: "return (id(ac_power_ratio).state == 10.0f) ? x * 10.0f : x;" + sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -44,7 +51,7 @@ sensor: register_type: holding address: 176 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -58,7 +65,7 @@ sensor: register_type: holding address: 177 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" @@ -72,7 +79,7 @@ sensor: register_type: holding address: 178 filters: - - lambda: 'return std::isnan(id(ac_power_ratio).state) ? x : x * id(ac_power_ratio).state;' + - lambda: ${func_scale_ac_power} unit_of_measurement: "W" device_class: power state_class: "measurement" From 8ffd3349ebe435d8015688cbc112d99cc65401eb Mon Sep 17 00:00:00 2001 From: Jerome Douven Date: Tue, 14 Jul 2026 00:42:26 +1000 Subject: [PATCH 3/3] fix(1P): mark AC power ratio register 54 as internal --- pv_inverter/packages/deye_hybrid_1p/grid.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pv_inverter/packages/deye_hybrid_1p/grid.yaml b/pv_inverter/packages/deye_hybrid_1p/grid.yaml index 7ff166c..ee2e195 100644 --- a/pv_inverter/packages/deye_hybrid_1p/grid.yaml +++ b/pv_inverter/packages/deye_hybrid_1p/grid.yaml @@ -41,6 +41,7 @@ sensor: accuracy_decimals: 0 entity_category: diagnostic icon: "mdi:multiplication" + internal: true - platform: modbus_controller modbus_controller_id: ${modbus_controller_id}