From dbe100b24bceff14b2aaa5c0b05d5a846185747b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 08:15:52 +0000 Subject: [PATCH] HomeWizard: support 1p kWh meters (#33293) --- meter/homewizard/connection.go | 23 +++++++++++++++---- meter/homewizard/types.go | 38 +++++++++++++++++--------------- meter/homewizard/types_test.go | 40 ++++++++++++++++++++++++---------- 3 files changed, 67 insertions(+), 34 deletions(-) diff --git a/meter/homewizard/connection.go b/meter/homewizard/connection.go index a79f5d4a1..4025f68c0 100644 --- a/meter/homewizard/connection.go +++ b/meter/homewizard/connection.go @@ -10,6 +10,7 @@ import ( "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/request" "github.com/evcc-io/evcc/util/transport" + "github.com/samber/lo" ) // Connection is the homewizard connection @@ -119,10 +120,17 @@ func (c *Connection) TotalEnergy() (float64, error) { // Currents implements the api.PhaseCurrents interface func (c *Connection) Currents() (float64, float64, float64, error) { res, err := c.dataG.Get() - if c.usage == "pv" { - return -res.ActiveCurrentL1A, -res.ActiveCurrentL2A, -res.ActiveCurrentL3A, err + + // 1p meters report the total instead of per-phase values + l1, l2, l3 := res.ActiveCurrentA, 0.0, 0.0 + if res.ActiveCurrentL1A != nil { + l1, l2, l3 = lo.FromPtr(res.ActiveCurrentL1A), lo.FromPtr(res.ActiveCurrentL2A), lo.FromPtr(res.ActiveCurrentL3A) } - return res.ActiveCurrentL1A, res.ActiveCurrentL2A, res.ActiveCurrentL3A, err + + if c.usage == "pv" { + return -l1, -l2, -l3, err + } + return l1, l2, l3, err } // Powers implements the api.PhasePowers interface @@ -137,5 +145,12 @@ func (c *Connection) Powers() (float64, float64, float64, error) { // Voltages implements the api.PhaseVoltages interface func (c *Connection) Voltages() (float64, float64, float64, error) { res, err := c.dataG.Get() - return res.ActiveVoltageL1V, res.ActiveVoltageL2V, res.ActiveVoltageL3V, err + + // 1p meters report the total instead of per-phase values + l1, l2, l3 := res.ActiveVoltageV, 0.0, 0.0 + if res.ActiveCurrentL1A != nil { + l1, l2, l3 = lo.FromPtr(res.ActiveVoltageL1V), lo.FromPtr(res.ActiveVoltageL2V), lo.FromPtr(res.ActiveVoltageL3V) + } + + return l1, l2, l3, err } diff --git a/meter/homewizard/types.go b/meter/homewizard/types.go index 20c3e4e86..f4926ec4e 100644 --- a/meter/homewizard/types.go +++ b/meter/homewizard/types.go @@ -16,22 +16,24 @@ type StateResponse struct { // DataResponse returns the most recent measurements from the HomeWizard device // https://homewizard-energy-api.readthedocs.io/endpoints.html#state-api-v1-state type DataResponse struct { - ActivePowerW float64 `json:"active_power_w"` - ActivePowerL1W float64 `json:"active_power_l1_w"` - ActivePowerL2W float64 `json:"active_power_l2_w"` - ActivePowerL3W float64 `json:"active_power_l3_w"` - TotalPowerImportT1kWh float64 `json:"total_power_import_t1_kwh"` - TotalPowerImportT2kWh float64 `json:"total_power_import_t2_kwh"` - TotalPowerImportT3kWh float64 `json:"total_power_import_t3_kwh"` - TotalPowerImportT4kWh float64 `json:"total_power_import_t4_kwh"` - TotalPowerExportT1kWh float64 `json:"total_power_export_t1_kwh"` - TotalPowerExportT2kWh float64 `json:"total_power_export_t2_kwh"` - TotalPowerExportT3kWh float64 `json:"total_power_export_t3_kwh"` - TotalPowerExportT4kWh float64 `json:"total_power_export_t4_kwh"` - ActiveCurrentL1A float64 `json:"active_current_l1_a"` - ActiveCurrentL2A float64 `json:"active_current_l2_a"` - ActiveCurrentL3A float64 `json:"active_current_l3_a"` - ActiveVoltageL1V float64 `json:"active_voltage_l1_v"` - ActiveVoltageL2V float64 `json:"active_voltage_l2_v"` - ActiveVoltageL3V float64 `json:"active_voltage_l3_v"` + ActivePowerW float64 `json:"active_power_w"` + ActivePowerL1W float64 `json:"active_power_l1_w"` + ActivePowerL2W float64 `json:"active_power_l2_w"` + ActivePowerL3W float64 `json:"active_power_l3_w"` + TotalPowerImportT1kWh float64 `json:"total_power_import_t1_kwh"` + TotalPowerImportT2kWh float64 `json:"total_power_import_t2_kwh"` + TotalPowerImportT3kWh float64 `json:"total_power_import_t3_kwh"` + TotalPowerImportT4kWh float64 `json:"total_power_import_t4_kwh"` + TotalPowerExportT1kWh float64 `json:"total_power_export_t1_kwh"` + TotalPowerExportT2kWh float64 `json:"total_power_export_t2_kwh"` + TotalPowerExportT3kWh float64 `json:"total_power_export_t3_kwh"` + TotalPowerExportT4kWh float64 `json:"total_power_export_t4_kwh"` + ActiveCurrentA float64 `json:"active_current_a"` + ActiveVoltageV float64 `json:"active_voltage_v"` + ActiveCurrentL1A *float64 `json:"active_current_l1_a"` + ActiveCurrentL2A *float64 `json:"active_current_l2_a"` + ActiveCurrentL3A *float64 `json:"active_current_l3_a"` + ActiveVoltageL1V *float64 `json:"active_voltage_l1_v"` + ActiveVoltageL2V *float64 `json:"active_voltage_l2_v"` + ActiveVoltageL3V *float64 `json:"active_voltage_l3_v"` } diff --git a/meter/homewizard/types_test.go b/meter/homewizard/types_test.go index 0a5ee4555..b13e74fde 100644 --- a/meter/homewizard/types_test.go +++ b/meter/homewizard/types_test.go @@ -47,12 +47,28 @@ func TestUnmarshalKwhDataResponse(t *testing.T) { assert.Equal(t, float64(28), res.ActivePowerL1W) assert.Equal(t, float64(0), res.ActivePowerL2W) assert.Equal(t, float64(-181), res.ActivePowerL3W) - assert.Equal(t, float64(235.4), res.ActiveVoltageL1V) - assert.Equal(t, float64(235.8), res.ActiveVoltageL2V) - assert.Equal(t, float64(236.1), res.ActiveVoltageL3V) - assert.Equal(t, float64(1.19), res.ActiveCurrentL1A) - assert.Equal(t, float64(0.37), res.ActiveCurrentL2A) - assert.Equal(t, float64(-0.93), res.ActiveCurrentL3A) + assert.Equal(t, float64(235.4), *res.ActiveVoltageL1V) + assert.Equal(t, float64(235.8), *res.ActiveVoltageL2V) + assert.Equal(t, float64(236.1), *res.ActiveVoltageL3V) + assert.Equal(t, float64(1.19), *res.ActiveCurrentL1A) + assert.Equal(t, float64(0.37), *res.ActiveCurrentL2A) + assert.Equal(t, float64(-0.93), *res.ActiveCurrentL3A) + } +} + +// Test homewizard kWh Meter 1-Phase response without per-phase current/voltage +func TestUnmarshalKwh1PhaseDataResponse(t *testing.T) { + { + var res DataResponse + // https://api-documentation.homewizard.com/docs/v1/measurement#kwh-meters-1-and-3-phase + jsonstr := `{"total_power_import_kwh":1.097,"total_power_import_t1_kwh":1.097,"total_power_export_kwh":0,"total_power_export_t1_kwh":0,"active_power_w":1381.396,"active_power_l1_w":1381.396,"active_voltage_v":228.641,"active_current_a":6.051,"active_apparent_current_a":6.068,"active_reactive_current_a":0.461,"active_apparent_power_va":1385.536,"active_reactive_power_var":-105.28,"active_power_factor":0.997,"active_frequency_hz":50}` + require.NoError(t, json.Unmarshal([]byte(jsonstr), &res)) + + assert.Equal(t, float64(1381.396), res.ActivePowerW) + assert.Equal(t, float64(1381.396), res.ActivePowerL1W) + assert.Equal(t, float64(228.641), res.ActiveVoltageV) + assert.Equal(t, float64(6.051), res.ActiveCurrentA) + assert.Nil(t, res.ActiveCurrentL1A) } } @@ -70,11 +86,11 @@ func TestUnmarshalP1DataResponse(t *testing.T) { assert.Equal(t, float64(-21), res.ActivePowerL1W) assert.Equal(t, float64(57), res.ActivePowerL2W) assert.Equal(t, float64(168), res.ActivePowerL3W) - assert.Equal(t, float64(228), res.ActiveVoltageL1V) - assert.Equal(t, float64(226), res.ActiveVoltageL2V) - assert.Equal(t, float64(225), res.ActiveVoltageL3V) - assert.Equal(t, float64(-0.092), res.ActiveCurrentL1A) - assert.Equal(t, float64(0.252), res.ActiveCurrentL2A) - assert.Equal(t, float64(0.747), res.ActiveCurrentL3A) + assert.Equal(t, float64(228), *res.ActiveVoltageL1V) + assert.Equal(t, float64(226), *res.ActiveVoltageL2V) + assert.Equal(t, float64(225), *res.ActiveVoltageL3V) + assert.Equal(t, float64(-0.092), *res.ActiveCurrentL1A) + assert.Equal(t, float64(0.252), *res.ActiveCurrentL2A) + assert.Equal(t, float64(0.747), *res.ActiveCurrentL3A) } }