api: split MeterEnergy into MeterImport and MeterExport (#29788)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
37e5659936
commit
7a5b1e7560
128 changed files with 570 additions and 435 deletions
13
api/api.go
13
api/api.go
|
|
@ -9,16 +9,21 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
//go:generate go tool mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterEnergy,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff
|
||||
//go:generate go tool mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterImport,MeterExport,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff
|
||||
|
||||
// Meter provides total active power in W
|
||||
type Meter interface {
|
||||
CurrentPower() (float64, error)
|
||||
}
|
||||
|
||||
// MeterEnergy provides total energy in kWh
|
||||
type MeterEnergy interface {
|
||||
TotalEnergy() (float64, error)
|
||||
// MeterImport provides total import in kWh
|
||||
type MeterImport interface {
|
||||
ImportEnergy() (float64, error)
|
||||
}
|
||||
|
||||
// MeterExport provides total export in kWh
|
||||
type MeterExport interface {
|
||||
ExportEnergy() (float64, error)
|
||||
}
|
||||
|
||||
// PhaseCurrents provides per-phase current A
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ func (d *decoratedMeter) Capability(typ reflect.Type) (any, bool) {
|
|||
return c, ok
|
||||
}
|
||||
|
||||
type testMeterEnergyImpl struct{}
|
||||
type testMeterImportImpl struct{}
|
||||
|
||||
func (t *testMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
func (t *testMeterImportImpl) ImportEnergy() (float64, error) {
|
||||
return 99.0, nil
|
||||
}
|
||||
|
||||
|
|
@ -32,13 +32,13 @@ func (t *testMeterImpl) CurrentPower() (float64, error) {
|
|||
}
|
||||
|
||||
func TestCap_DirectTypeAssertion(t *testing.T) {
|
||||
// concrete type that directly implements MeterEnergy
|
||||
impl := &testMeterEnergyImpl{}
|
||||
// concrete type that directly implements MeterImport
|
||||
impl := &testMeterImportImpl{}
|
||||
|
||||
me, ok := Cap[MeterEnergy](impl)
|
||||
me, ok := Cap[MeterImport](impl)
|
||||
require.True(t, ok)
|
||||
|
||||
energy, err := me.TotalEnergy()
|
||||
energy, err := me.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 99.0, energy)
|
||||
}
|
||||
|
|
@ -49,15 +49,15 @@ func TestCap_CapableRegistryLookup(t *testing.T) {
|
|||
decorated := &decoratedMeter{
|
||||
Meter: base,
|
||||
caps: map[reflect.Type]any{
|
||||
reflect.TypeFor[MeterEnergy](): &testMeterEnergyImpl{},
|
||||
reflect.TypeFor[MeterImport](): &testMeterImportImpl{},
|
||||
},
|
||||
}
|
||||
|
||||
// should find MeterEnergy via registry
|
||||
me, ok := Cap[MeterEnergy](decorated)
|
||||
// should find MeterImport via registry
|
||||
me, ok := Cap[MeterImport](decorated)
|
||||
require.True(t, ok)
|
||||
|
||||
energy, err := me.TotalEnergy()
|
||||
energy, err := me.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 99.0, energy)
|
||||
|
||||
|
|
@ -81,11 +81,11 @@ func TestCap_ExtractedCapabilityLosesRegistry(t *testing.T) {
|
|||
// Reproduces https://github.com/evcc-io/evcc/issues/28915
|
||||
// When a Meter is extracted from a decorated charger via Cap[Meter],
|
||||
// the extracted impl does NOT carry the Capable interface, so
|
||||
// subsequent Cap[MeterEnergy] on the extracted value fails.
|
||||
// subsequent Cap[MeterImport] on the extracted value fails.
|
||||
decorated := &decoratedCharger{
|
||||
caps: map[reflect.Type]any{
|
||||
reflect.TypeFor[Meter](): &testMeterImpl{},
|
||||
reflect.TypeFor[MeterEnergy](): &testMeterEnergyImpl{},
|
||||
reflect.TypeFor[MeterImport](): &testMeterImportImpl{},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -93,9 +93,9 @@ func TestCap_ExtractedCapabilityLosesRegistry(t *testing.T) {
|
|||
mt, ok := Cap[Meter](decorated)
|
||||
require.True(t, ok)
|
||||
|
||||
// Bug: extracted meter cannot find MeterEnergy because it's a standalone impl
|
||||
_, ok = Cap[MeterEnergy](mt)
|
||||
assert.False(t, ok, "extracted meter should NOT have MeterEnergy capability")
|
||||
// Bug: extracted meter cannot find MeterImport because it's a standalone impl
|
||||
_, ok = Cap[MeterImport](mt)
|
||||
assert.False(t, ok, "extracted meter should NOT have MeterImport capability")
|
||||
|
||||
// Fix: wrapping extracted meter with source's Capable preserves registry
|
||||
type capableMeter struct {
|
||||
|
|
@ -104,32 +104,32 @@ func TestCap_ExtractedCapabilityLosesRegistry(t *testing.T) {
|
|||
}
|
||||
wrapped := &capableMeter{Meter: mt, Capable: decorated}
|
||||
|
||||
me, ok := Cap[MeterEnergy](wrapped)
|
||||
require.True(t, ok, "wrapped meter should find MeterEnergy via Capable")
|
||||
me, ok := Cap[MeterImport](wrapped)
|
||||
require.True(t, ok, "wrapped meter should find MeterImport via Capable")
|
||||
|
||||
energy, err := me.TotalEnergy()
|
||||
energy, err := me.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 99.0, energy)
|
||||
}
|
||||
|
||||
func TestCap_NilValue(t *testing.T) {
|
||||
_, ok := Cap[MeterEnergy](nil)
|
||||
_, ok := Cap[MeterImport](nil)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestCap_DirectTakesPrecedence(t *testing.T) {
|
||||
// type that both directly implements AND has registry
|
||||
type directAndCapable struct {
|
||||
testMeterEnergyImpl
|
||||
testMeterImportImpl
|
||||
caps map[reflect.Type]any //nolint:unused
|
||||
}
|
||||
|
||||
v := &directAndCapable{}
|
||||
|
||||
me, ok := Cap[MeterEnergy](v)
|
||||
me, ok := Cap[MeterImport](v)
|
||||
require.True(t, ok)
|
||||
|
||||
energy, err := me.TotalEnergy()
|
||||
energy, err := me.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 99.0, energy)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,19 +203,34 @@ func (i *iChargeState) Status() (api.ChargeStatus, error) {
|
|||
return i.chargeState0()
|
||||
}
|
||||
|
||||
func MeterEnergy(meterEnergy0 func() (float64, error)) api.MeterEnergy {
|
||||
if meterEnergy0 == nil {
|
||||
func MeterImport(meterImport0 func() (float64, error)) api.MeterImport {
|
||||
if meterImport0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iMeterEnergy{meterEnergy0}
|
||||
return &iMeterImport{meterImport0}
|
||||
}
|
||||
|
||||
type iMeterEnergy struct {
|
||||
meterEnergy0 func() (float64, error)
|
||||
type iMeterImport struct {
|
||||
meterImport0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iMeterEnergy) TotalEnergy() (float64, error) {
|
||||
return i.meterEnergy0()
|
||||
func (i *iMeterImport) ImportEnergy() (float64, error) {
|
||||
return i.meterImport0()
|
||||
}
|
||||
|
||||
func MeterExport(meterExport0 func() (float64, error)) api.MeterExport {
|
||||
if meterExport0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iMeterExport{meterExport0}
|
||||
}
|
||||
|
||||
type iMeterExport struct {
|
||||
meterExport0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iMeterExport) ExportEnergy() (float64, error) {
|
||||
return i.meterExport0()
|
||||
}
|
||||
|
||||
func PhaseCurrents(phaseCurrents0 func() (float64, float64, float64, error)) api.PhaseCurrents {
|
||||
|
|
|
|||
77
api/mock.go
77
api/mock.go
|
|
@ -1,9 +1,9 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/evcc-io/evcc/api (interfaces: Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterEnergy,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff)
|
||||
// Source: github.com/evcc-io/evcc/api (interfaces: Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterImport,MeterExport,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterEnergy,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff
|
||||
// mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterImport,MeterExport,PhaseCurrents,Vehicle,ConnectionTimer,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Dimmer,Tariff
|
||||
//
|
||||
|
||||
// Package api is a generated GoMock package.
|
||||
|
|
@ -409,43 +409,82 @@ func (mr *MockMeterMockRecorder) CurrentPower() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentPower", reflect.TypeOf((*MockMeter)(nil).CurrentPower))
|
||||
}
|
||||
|
||||
// MockMeterEnergy is a mock of MeterEnergy interface.
|
||||
type MockMeterEnergy struct {
|
||||
// MockMeterImport is a mock of MeterImport interface.
|
||||
type MockMeterImport struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockMeterEnergyMockRecorder
|
||||
recorder *MockMeterImportMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockMeterEnergyMockRecorder is the mock recorder for MockMeterEnergy.
|
||||
type MockMeterEnergyMockRecorder struct {
|
||||
mock *MockMeterEnergy
|
||||
// MockMeterImportMockRecorder is the mock recorder for MockMeterImport.
|
||||
type MockMeterImportMockRecorder struct {
|
||||
mock *MockMeterImport
|
||||
}
|
||||
|
||||
// NewMockMeterEnergy creates a new mock instance.
|
||||
func NewMockMeterEnergy(ctrl *gomock.Controller) *MockMeterEnergy {
|
||||
mock := &MockMeterEnergy{ctrl: ctrl}
|
||||
mock.recorder = &MockMeterEnergyMockRecorder{mock}
|
||||
// NewMockMeterImport creates a new mock instance.
|
||||
func NewMockMeterImport(ctrl *gomock.Controller) *MockMeterImport {
|
||||
mock := &MockMeterImport{ctrl: ctrl}
|
||||
mock.recorder = &MockMeterImportMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockMeterEnergy) EXPECT() *MockMeterEnergyMockRecorder {
|
||||
func (m *MockMeterImport) EXPECT() *MockMeterImportMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// TotalEnergy mocks base method.
|
||||
func (m *MockMeterEnergy) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy mocks base method.
|
||||
func (m *MockMeterImport) ImportEnergy() (float64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TotalEnergy")
|
||||
ret := m.ctrl.Call(m, "ImportEnergy")
|
||||
ret0, _ := ret[0].(float64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// TotalEnergy indicates an expected call of TotalEnergy.
|
||||
func (mr *MockMeterEnergyMockRecorder) TotalEnergy() *gomock.Call {
|
||||
// ImportEnergy indicates an expected call of ImportEnergy.
|
||||
func (mr *MockMeterImportMockRecorder) ImportEnergy() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalEnergy", reflect.TypeOf((*MockMeterEnergy)(nil).TotalEnergy))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImportEnergy", reflect.TypeOf((*MockMeterImport)(nil).ImportEnergy))
|
||||
}
|
||||
|
||||
// MockMeterExport is a mock of MeterExport interface.
|
||||
type MockMeterExport struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockMeterExportMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockMeterExportMockRecorder is the mock recorder for MockMeterExport.
|
||||
type MockMeterExportMockRecorder struct {
|
||||
mock *MockMeterExport
|
||||
}
|
||||
|
||||
// NewMockMeterExport creates a new mock instance.
|
||||
func NewMockMeterExport(ctrl *gomock.Controller) *MockMeterExport {
|
||||
mock := &MockMeterExport{ctrl: ctrl}
|
||||
mock.recorder = &MockMeterExportMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockMeterExport) EXPECT() *MockMeterExportMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ExportEnergy mocks base method.
|
||||
func (m *MockMeterExport) ExportEnergy() (float64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ExportEnergy")
|
||||
ret0, _ := ret[0].(float64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ExportEnergy indicates an expected call of ExportEnergy.
|
||||
func (mr *MockMeterExportMockRecorder) ExportEnergy() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportEnergy", reflect.TypeOf((*MockMeterExport)(nil).ExportEnergy))
|
||||
}
|
||||
|
||||
// MockPhaseCurrents is a mock of PhaseCurrents interface.
|
||||
|
|
|
|||
|
|
@ -95,10 +95,10 @@ func (wb *Blueprint) ChargedEnergy() (float64, error) {
|
|||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Blueprint)(nil)
|
||||
var _ api.MeterImport = (*Blueprint)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Blueprint) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Blueprint) ImportEnergy() (float64, error) {
|
||||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ func (wb *ABB) CurrentPower() (float64, error) {
|
|||
|
||||
var _ api.ChargeRater = (*ABB)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *ABB) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(abbRegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -197,10 +197,10 @@ func (wb *AblEm4) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*AblEm4)(nil)
|
||||
var _ api.MeterImport = (*AblEm4)(nil)
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *AblEm4) TotalEnergy() (float64, error) {
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *AblEm4) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wb.base+abl4RegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -210,10 +210,10 @@ func (wb *Alfen) CurrentPower() (float64, error) {
|
|||
return rs485.RTUIeee754ToFloat64(b), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Alfen)(nil)
|
||||
var _ api.MeterImport = (*Alfen)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Alfen) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Alfen) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(alfenRegEnergy, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -211,10 +211,10 @@ func (wb *AlpitronicHYC) ChargedEnergy() (float64, error) {
|
|||
return float64(encoding.Uint16(b)) / 100, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*AlpitronicHYC)(nil)
|
||||
var _ api.MeterImport = (*AlpitronicHYC)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *AlpitronicHYC) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *AlpitronicHYC) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(wb.reg(hycRegTotalChargedEnergy), 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -255,10 +255,10 @@ func (wb *Amperfied) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint16(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Amperfied)(nil)
|
||||
var _ api.MeterImport = (*Amperfied)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Amperfied) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Amperfied) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(ampRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration)
|
|||
if b, err := wb.conn.ReadHoldingRegisters(reg, 2); err == nil && binary.BigEndian.Uint32(b) != math.MaxUint32 {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
|
||||
// check presence of "ocpp meter"
|
||||
if b, err := wb.conn.ReadHoldingRegisters(bendRegVoltages, 2); err == nil && binary.BigEndian.Uint32(b) > 0 {
|
||||
|
|
@ -374,7 +374,7 @@ func (wb *BenderCC) currentPower() (float64, error) {
|
|||
// removed: https://github.com/evcc-io/evcc/issues/13726
|
||||
// var _ api.ChargeRater = (*BenderCC)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *BenderCC) totalEnergy() (float64, error) {
|
||||
if wb.legacy {
|
||||
b, err := wb.conn.ReadHoldingRegisters(bendRegPhaseEnergy, 6)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ func NewCfosPowerBrain(ctx context.Context, uri string, id uint8) (api.Charger,
|
|||
// decorate meter
|
||||
if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeter, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
|
||||
if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeterFlags, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
|
|
@ -156,7 +156,7 @@ func (wb *CfosPowerBrain) currentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *CfosPowerBrain) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(cfosRegEnergy, 4)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -145,12 +145,12 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
implement.May(c, implement.SocLimiter(limitsoc))
|
||||
|
||||
// decorate measurements
|
||||
powerG, energyG, err := cc.Energy.Configure(ctx)
|
||||
powerG, importG, _, err := cc.Energy.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.Meter(powerG))
|
||||
implement.May(c, implement.MeterEnergy(energyG))
|
||||
implement.May(c, implement.MeterImport(importG))
|
||||
|
||||
currentsG, voltagesG, _, err := cc.Phases.Configure(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ func (wb *Compleo) CurrentPower() (float64, error) {
|
|||
|
||||
var _ api.ChargeRater = (*Compleo)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *Compleo) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(wb.reg(compleoRegEnergy), 1)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -162,10 +162,10 @@ func (wb *ConnectIq) CurrentPower() (float64, error) {
|
|||
return (res.Pow[0] + res.Pow[1] + res.Pow[2]) * 1e3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*ConnectIq)(nil)
|
||||
var _ api.MeterImport = (*ConnectIq)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *ConnectIq) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *ConnectIq) ImportEnergy() (float64, error) {
|
||||
var res connectiq.MeterRead
|
||||
uri := fmt.Sprintf("%s/meter/read", wb.uri)
|
||||
err := wb.GetJSON(uri, &res)
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@ func (wb *Dadapower) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Dadapower)(nil)
|
||||
var _ api.MeterImport = (*Dadapower)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Dadapower) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Dadapower) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(dadapowerRegEnergyImportTotal+wb.regOffset, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -250,10 +250,10 @@ func (wb *DaheimLaden) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*DaheimLaden)(nil)
|
||||
var _ api.MeterImport = (*DaheimLaden)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *DaheimLaden) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *DaheimLaden) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(dlRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -362,9 +362,9 @@ func (wb *E3dc) CurrentPower() (float64, error) {
|
|||
return p1 + p2 + p3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*E3dc)(nil)
|
||||
var _ api.MeterImport = (*E3dc)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
//
|
||||
// E3DC stores wallbox energy in two separate counters that must be added:
|
||||
// - DB_TEC_WALLBOX_ENERGYALL: Historical energy stored in the database (persisted)
|
||||
|
|
@ -372,7 +372,7 @@ var _ api.MeterEnergy = (*E3dc)(nil)
|
|||
//
|
||||
// The sum of both values matches the total energy shown in the E3DC portal.
|
||||
// Testing showed: DB_TEC (8319 kWh) + WB_ENERGY (699 kWh) = 9018 kWh ≈ Portal (9019 kWh)
|
||||
func (wb *E3dc) TotalEnergy() (float64, error) {
|
||||
func (wb *E3dc) ImportEnergy() (float64, error) {
|
||||
// Query both energy sources sequentially
|
||||
res, err := wb.conn.Send(*rscp.NewMessage(rscp.DB_REQ_TEC_WALLBOX_VALUES, nil))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -717,10 +717,10 @@ func (c *Easee) Currents() (float64, float64, float64, error) {
|
|||
return c.currentL1, c.currentL2, c.currentL3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Easee)(nil)
|
||||
var _ api.MeterImport = (*Easee)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *Easee) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *Easee) ImportEnergy() (float64, error) {
|
||||
c.mux.RLock()
|
||||
defer c.mux.RUnlock()
|
||||
// updates for this are only sent once an hour, so inaccurate by design
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ func TestChargeSessionStart_SetsFields(t *testing.T) {
|
|||
|
||||
assert.Equal(t, 801, e.currentSessionID)
|
||||
|
||||
total, err := e.TotalEnergy()
|
||||
total, err := e.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 9141.414622, total)
|
||||
}
|
||||
|
|
@ -581,7 +581,7 @@ func TestChargingSession_UpdatesBothWhenIdMatches(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, 16.2, charged)
|
||||
|
||||
total, err := e.TotalEnergy()
|
||||
total, err := e.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 9173.5, total)
|
||||
}
|
||||
|
|
@ -600,7 +600,7 @@ func TestChargingSession_MismatchedId_ProtectsSessionEnergy(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, 5.0, charged) // sessionEnergy unchanged
|
||||
|
||||
total, err := e.TotalEnergy()
|
||||
total, err := e.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 9173.5, total) // totalEnergy updated
|
||||
}
|
||||
|
|
@ -619,18 +619,18 @@ func TestChargingSession_AtStartup_ProtectsSessionEnergy(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0.0, charged) // sessionEnergy protected (Id 803 != 0)
|
||||
|
||||
total, err := e.TotalEnergy()
|
||||
total, err := e.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 9173.5, total) // totalEnergy updated
|
||||
}
|
||||
|
||||
func TestLifetimeEnergy_DoesNotDecreaseTotalEnergy(t *testing.T) {
|
||||
func TestLifetimeEnergy_DoesNotDecreaseImportEnergy(t *testing.T) {
|
||||
e := newEasee()
|
||||
e.totalEnergy = 9173.5
|
||||
|
||||
e.ProductUpdate(createPayload(easee.LIFETIME_ENERGY, time.Now(), easee.Double, "9170.0"))
|
||||
|
||||
total, err := e.TotalEnergy()
|
||||
total, err := e.ImportEnergy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 9173.5, total)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,10 +216,10 @@ func (wb *Em2GoDuo) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Em2GoDuo)(nil)
|
||||
var _ api.MeterImport = (*Em2GoDuo)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Em2GoDuo) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Em2GoDuo) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wb.base+em2GoDuoRegConEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -288,10 +288,10 @@ func (wb *Em2Go) CurrentPower() (float64, error) {
|
|||
return rs485.RTUUint32ToFloat64(b), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Em2Go)(nil)
|
||||
var _ api.MeterImport = (*Em2Go)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Em2Go) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Em2Go) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(em2GoRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -186,10 +186,10 @@ func (wb *EProWallbox) CurrentPower() (float64, error) {
|
|||
return l1 + l2 + l3, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*EProWallbox)(nil)
|
||||
var _ api.MeterImport = (*EProWallbox)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *EProWallbox) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *EProWallbox) ImportEnergy() (float64, error) {
|
||||
l1, l2, l3, err := wb.getPhaseValues(eproRegActiveEnergies, 1000)
|
||||
return -(l1 + l2 + l3), err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func NewEtekFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
// Check energy register (95)
|
||||
if b, err := wb.conn.ReadHoldingRegisters(etekRegMeterEnergyAddr, 1); err == nil {
|
||||
if binary.BigEndian.Uint16(b) != etekRegInvalidMeterAddr {
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ func (wb *Etek) currentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint16(b)), nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *Etek) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(etekRegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -314,10 +314,10 @@ func (wb *EVECUBE) CurrentPower() (float64, error) {
|
|||
return status.Voltage * status.Current, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*EVECUBE)(nil)
|
||||
var _ api.MeterImport = (*EVECUBE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *EVECUBE) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *EVECUBE) ImportEnergy() (float64, error) {
|
||||
status, err := wb.getStatus()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const (
|
|||
evsemasterConnectTimeout = 15 * time.Second
|
||||
)
|
||||
|
||||
// EVSEMaster implements api.Charger (and api.Meter / api.MeterEnergy /
|
||||
// EVSEMaster implements api.Charger (and api.Meter / api.MeterImport /
|
||||
// api.PhaseCurrents / api.PhaseVoltages) for charging stations that use the
|
||||
// EVSE Master UDP protocol – e.g. Sync EV and generic Chinese EVSE devices.
|
||||
//
|
||||
|
|
@ -288,10 +288,10 @@ func (wb *EVSEMaster) CurrentPower() (float64, error) {
|
|||
return res.Power, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*EVSEMaster)(nil)
|
||||
var _ api.MeterImport = (*EVSEMaster)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface.
|
||||
func (wb *EVSEMaster) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface.
|
||||
func (wb *EVSEMaster) ImportEnergy() (float64, error) {
|
||||
res, err := wb.data.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func NewEVSEWifiFromConfig(other map[string]any) (api.Charger, error) {
|
|||
}
|
||||
|
||||
if cc.Meter.Energy {
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
}
|
||||
|
||||
if cc.Meter.Currents {
|
||||
|
|
@ -210,7 +210,7 @@ func (wb *EVSEWifi) currentPower() (float64, error) {
|
|||
return 1000 * params.ActualPower, err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *EVSEWifi) totalEnergy() (float64, error) {
|
||||
params, err := wb.paramG.Get()
|
||||
return params.MeterReading, err
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ func TestEvseWifi(t *testing.T) {
|
|||
t.Error("missing api.Meter")
|
||||
}
|
||||
|
||||
if _, ok := api.Cap[api.MeterEnergy](wb); !ok {
|
||||
t.Error("missing api.MeterEnergy")
|
||||
if _, ok := api.Cap[api.MeterImport](wb); !ok {
|
||||
t.Error("missing api.MeterImport")
|
||||
}
|
||||
|
||||
if _, ok := api.Cap[api.PhaseCurrents](wb); !ok {
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ func (c *FritzDECT) Enable(enable bool) error {
|
|||
return c.conn.SwitchOff()
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*FritzDECT)(nil)
|
||||
var _ api.MeterImport = (*FritzDECT)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *FritzDECT) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *FritzDECT) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,10 +207,10 @@ func (c *GoE) Identify() (string, error) {
|
|||
return resp.Identify(), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*GoE)(nil)
|
||||
var _ api.MeterImport = (*GoE)(nil)
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface - v2 only
|
||||
func (c *GoE) TotalEnergy() (float64, error) {
|
||||
// totalEnergy implements the api.MeterImport interface - v2 only
|
||||
func (c *GoE) ImportEnergy() (float64, error) {
|
||||
resp, err := c.api.Status()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ func TestGoEV2(t *testing.T) {
|
|||
t.Error("missing Identifier api")
|
||||
}
|
||||
|
||||
if _, ok := api.Cap[api.MeterEnergy](wb); !ok {
|
||||
t.Error("missing MeterEnergy api")
|
||||
if _, ok := api.Cap[api.MeterImport](wb); !ok {
|
||||
t.Error("missing MeterImport api")
|
||||
}
|
||||
|
||||
if _, ok := api.Cap[api.PhaseSwitcher](wb); !ok {
|
||||
|
|
|
|||
|
|
@ -206,10 +206,10 @@ func (wb *HardyBarth) CurrentPower() (float64, error) {
|
|||
return res.Data[obis.PowerConsumption], nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*HardyBarth)(nil)
|
||||
var _ api.MeterImport = (*HardyBarth)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *HardyBarth) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *HardyBarth) ImportEnergy() (float64, error) {
|
||||
res, err := wb.meterG()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ func NewSalia(ctx context.Context, uri, user, password string, cache time.Durati
|
|||
|
||||
if res.Secc.Port0.Metering.Meter.Available > 0 {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +266,7 @@ func (wb *Salia) currentPower() (float64, error) {
|
|||
return res.Secc.Port0.Metering.Power.ActiveTotal.Actual / 10, err
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *Salia) totalEnergy() (float64, error) {
|
||||
res, err := wb.apiG.Get()
|
||||
return res.Secc.Port0.Metering.Energy.ActiveImport.Actual / 1e3, err
|
||||
|
|
|
|||
|
|
@ -80,12 +80,12 @@ func NewHeatpumpFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
return nil, err
|
||||
}
|
||||
|
||||
powerG, energyG, err := cc.Energy.Configure(ctx)
|
||||
powerG, importG, _, err := cc.Energy.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
implement.May(res, implement.MeterImport(importG))
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -251,10 +251,10 @@ func (wb *HeidelbergEC) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint16(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*HeidelbergEC)(nil)
|
||||
var _ api.MeterImport = (*HeidelbergEC)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *HeidelbergEC) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *HeidelbergEC) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(hecRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -165,10 +165,10 @@ func (wb *Hesotec) ChargeDuration() (time.Duration, error) {
|
|||
return time.Duration(binary.BigEndian.Uint32(b)) * time.Second, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Hesotec)(nil)
|
||||
var _ api.MeterImport = (*Hesotec)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Hesotec) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Hesotec) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(hesotecRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
implement.Has(c, implement.Meter(func() (float64, error) { return conn.GetFloatState(cc.Power) }))
|
||||
}
|
||||
if cc.Energy != "" {
|
||||
implement.Has(c, implement.MeterEnergy(func() (float64, error) { return conn.GetFloatState(cc.Energy) }))
|
||||
implement.Has(c, implement.MeterImport(func() (float64, error) { return conn.GetFloatState(cc.Energy) }))
|
||||
}
|
||||
|
||||
// phase currents (optional)
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ func (c *CCU) Enable(enable bool) error {
|
|||
return c.conn.Enable(enable)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*CCU)(nil)
|
||||
var _ api.MeterImport = (*CCU)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *CCU) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *CCU) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ func (c *HomeWizard) Enable(enable bool) error {
|
|||
return c.conn.Enable(enable)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*HomeWizard)(nil)
|
||||
var _ api.MeterImport = (*HomeWizard)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *HomeWizard) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *HomeWizard) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func NewInnogyFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
|
||||
// check presence of energy meter & voltages registers
|
||||
if b, err := wb.conn.ReadInputRegisters(igyRegModbusTableVersion, 1); err == nil && binary.BigEndian.Uint16(b) >= 6 {
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
wb.hasVoltages = true
|
||||
}
|
||||
|
|
@ -226,7 +226,7 @@ func (wb *Innogy) voltages() (float64, float64, float64, error) {
|
|||
return res[0], res[1], res[2], nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *Innogy) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(igyRegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -314,10 +314,10 @@ func (wb *Kathrein) Voltages() (float64, float64, float64, error) {
|
|||
// removed since broken, see https://github.com/evcc-io/evcc/pull/25427
|
||||
// var _ api.ChargeRater = (*Kathrein)(nil)
|
||||
|
||||
var _ api.MeterEnergy = (*Kathrein)(nil)
|
||||
var _ api.MeterImport = (*Kathrein)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Kathrein) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Kathrein) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(kathreinRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ func NewKebaFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
|
||||
if hasEnergyMeter {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ func (wb *Keba) currentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)) / 1e3, nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *Keba) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(kebaRegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func NewKebaUdpFromConfig(other map[string]any) (api.Charger, error) {
|
|||
|
||||
if energy > 0 {
|
||||
implement.Has(k, implement.Meter(k.currentPower))
|
||||
implement.Has(k, implement.MeterEnergy(k.totalEnergy))
|
||||
implement.Has(k, implement.MeterImport(k.totalEnergy))
|
||||
implement.Has(k, implement.PhaseCurrents(k.currents))
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +284,7 @@ func (c *KebaUdp) currentPower() (float64, error) {
|
|||
return float64(kr.P) / 1e3, err
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (c *KebaUdp) totalEnergy() (float64, error) {
|
||||
var kr keba.Report3
|
||||
err := c.roundtrip("report", 3, &kr)
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func (wb *KSE) CurrentPower() (float64, error) {
|
|||
|
||||
var _ api.ChargeRater = (*KSE)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *KSE) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(kseRegCurrentLoadedEnergy, 1)
|
||||
if err != nil {
|
||||
|
|
@ -191,10 +191,10 @@ func (wb *KSE) ChargedEnergy() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint16(b)) / 100, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*KSE)(nil)
|
||||
var _ api.MeterImport = (*KSE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *KSE) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *KSE) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(kseRegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -251,10 +251,10 @@ func (wb *Lektrico) CurrentPower() (float64, error) {
|
|||
return res.InstantPower, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Lektrico)(nil)
|
||||
var _ api.MeterImport = (*Lektrico)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Lektrico) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Lektrico) ImportEnergy() (float64, error) {
|
||||
res, err := wb.statusG.Get()
|
||||
return res.TotalChargedEnergy, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,23 +9,39 @@ import (
|
|||
|
||||
type Energy struct {
|
||||
Power *plugin.Config // optional
|
||||
Energy *plugin.Config // optional
|
||||
Import *plugin.Config // optional
|
||||
Export *plugin.Config // optional
|
||||
// Energy is a legacy alias for Import. Chargers always import energy, so
|
||||
// the alias only feeds the Import getter (unlike meters, which alias to both).
|
||||
Energy *plugin.Config
|
||||
}
|
||||
|
||||
func (cc *Energy) Configure(ctx context.Context) (
|
||||
func() (float64, error),
|
||||
func() (float64, error),
|
||||
func() (float64, error),
|
||||
error,
|
||||
) {
|
||||
powerG, err := cc.Power.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("power: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("power: %w", err)
|
||||
}
|
||||
|
||||
energyG, err := cc.Energy.FloatGetter(ctx)
|
||||
// legacy: chargers always import, so 'energy' aliases to import only.
|
||||
importCfg := cc.Import
|
||||
if cc.Energy != nil && importCfg == nil {
|
||||
importCfg = cc.Energy
|
||||
}
|
||||
|
||||
importG, err := importCfg.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("energy: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("import: %w", err)
|
||||
}
|
||||
|
||||
return powerG, energyG, nil
|
||||
exportG, err := cc.Export.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("export: %w", err)
|
||||
}
|
||||
|
||||
return powerG, importG, exportG, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,10 +212,10 @@ func (wb *MennekesCompact) CurrentPower() (float64, error) {
|
|||
return float64(encoding.Float32(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*MennekesCompact)(nil)
|
||||
var _ api.MeterImport = (*MennekesCompact)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *MennekesCompact) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *MennekesCompact) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(mennekesRegChargedEnergyTotal, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
@ -256,7 +256,7 @@ func (wb *MennekesCompact) getPhaseValues(reg uint16) (float64, float64, float64
|
|||
/*
|
||||
var _ api.ChargeRater = (*MennekesCompact)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *MennekesCompact) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(mennekesRegChargedEnergySession, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ func (wb *MennekesHcc3) CurrentPower() (float64, error) {
|
|||
|
||||
var _ api.ChargeRater = (*MennekesHcc3)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *MennekesHcc3) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(mennekesHcc3RegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -254,10 +254,10 @@ func (wb *Nexblue) ChargedEnergy() (float64, error) {
|
|||
return res.Energy, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Nexblue)(nil)
|
||||
var _ api.MeterImport = (*Nexblue)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Nexblue) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Nexblue) ImportEnergy() (float64, error) {
|
||||
res, err := wb.statusG.Get()
|
||||
return res.LifetimeEnergy, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,10 +283,10 @@ func (wb *NRGKickBLE) CurrentPower() (float64, error) {
|
|||
return float64(res.TotalPower) * 10, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*NRGKickBLE)(nil)
|
||||
var _ api.MeterImport = (*NRGKickBLE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *NRGKickBLE) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *NRGKickBLE) ImportEnergy() (float64, error) {
|
||||
var res ble.Energy
|
||||
if err := wb.read(ble.EnergyService, &res); err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@ func (nrg *NRGKickConnect) CurrentPower() (float64, error) {
|
|||
return res.ChargingPower * 1e3, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*NRGKickConnect)(nil)
|
||||
var _ api.MeterImport = (*NRGKickConnect)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (nrg *NRGKickConnect) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (nrg *NRGKickConnect) ImportEnergy() (float64, error) {
|
||||
res, err := nrg.measurementsG.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -228,10 +228,10 @@ func (nrg *NRGKickGen2) CurrentPower() (float64, error) {
|
|||
return float64(encoding.Int32LswFirst(b)) * 1e-3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*NRGKickGen2)(nil)
|
||||
var _ api.MeterImport = (*NRGKickGen2)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (nrg *NRGKickGen2) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (nrg *NRGKickGen2) ImportEnergy() (float64, error) {
|
||||
b, err := nrg.conn.ReadHoldingRegisters(nrgKickGen2TotalChargedEnergy, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ func NewOCPPFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandEnergyActiveImportRegister) {
|
||||
implement.Has(c, implement.MeterEnergy(c.conn.TotalEnergy))
|
||||
implement.Has(c, implement.MeterImport(c.conn.ImportEnergy))
|
||||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandCurrentImport) {
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ func (conn *Connector) CurrentPower() (float64, error) {
|
|||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
func (conn *Connector) TotalEnergy() (float64, error) {
|
||||
func (conn *Connector) ImportEnergy() (float64, error) {
|
||||
if !conn.cp.Connected() {
|
||||
return 0, api.ErrTimeout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ func (suite *connTestSuite) TestConnectorNoMeasurements() {
|
|||
suite.Equal(api.ErrTimeout, err, "GetMaxCurrent")
|
||||
|
||||
// api.ErrNotAvailable
|
||||
_, err = suite.conn.TotalEnergy()
|
||||
suite.Equal(api.ErrNotAvailable, err, "TotalEnergy")
|
||||
_, err = suite.conn.ImportEnergy()
|
||||
suite.Equal(api.ErrNotAvailable, err, "ImportEnergy")
|
||||
_, err = suite.conn.Soc()
|
||||
suite.Equal(api.ErrNotAvailable, err, "Soc")
|
||||
_, _, _, err = suite.conn.Voltages()
|
||||
|
|
@ -98,9 +98,9 @@ func (suite *connTestSuite) TestConnectorMeasurementsNoTxn() {
|
|||
suite.Equal(api.ErrTimeout, err, "GetMaxCurrent")
|
||||
|
||||
// keep old values
|
||||
res, err = suite.conn.TotalEnergy()
|
||||
suite.NoError(err, "TotalEnergy")
|
||||
suite.Equal(res, 0.001, "TotalEnergy")
|
||||
res, err = suite.conn.ImportEnergy()
|
||||
suite.NoError(err, "ImportEnergy")
|
||||
suite.Equal(res, 0.001, "ImportEnergy")
|
||||
res, err = suite.conn.Soc()
|
||||
suite.NoError(err, "Soc")
|
||||
suite.Equal(res, 1.0, "Soc")
|
||||
|
|
@ -119,8 +119,8 @@ func (suite *connTestSuite) TestConnectorMeasurementsRunningTxnOutdated() {
|
|||
|
||||
_, err := suite.conn.CurrentPower()
|
||||
suite.Equal(api.ErrTimeout, err, "CurrentPower")
|
||||
_, err = suite.conn.TotalEnergy()
|
||||
suite.Equal(api.ErrTimeout, err, "TotalEnergy")
|
||||
_, err = suite.conn.ImportEnergy()
|
||||
suite.Equal(api.ErrTimeout, err, "ImportEnergy")
|
||||
_, err = suite.conn.GetMaxCurrent()
|
||||
suite.Equal(api.ErrTimeout, err, "GetMaxCurrent")
|
||||
_, err = suite.conn.Soc()
|
||||
|
|
@ -140,8 +140,8 @@ func (suite *connTestSuite) TestConnectorMeasurementsRunningTxn() {
|
|||
|
||||
_, err := suite.conn.CurrentPower()
|
||||
suite.NoError(err, "CurrentPower")
|
||||
_, err = suite.conn.TotalEnergy()
|
||||
suite.NoError(err, "TotalEnergy")
|
||||
_, err = suite.conn.ImportEnergy()
|
||||
suite.NoError(err, "ImportEnergy")
|
||||
_, err = suite.conn.GetMaxCurrent()
|
||||
suite.NoError(err, "GetMaxCurrent")
|
||||
_, err = suite.conn.Soc()
|
||||
|
|
|
|||
|
|
@ -213,10 +213,10 @@ func (c *OpenEVSE) ChargeDuration() (time.Duration, error) {
|
|||
return time.Duration(res.Elapsed) * time.Second, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*OpenEVSE)(nil)
|
||||
var _ api.MeterImport = (*OpenEVSE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *OpenEVSE) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *OpenEVSE) ImportEnergy() (float64, error) {
|
||||
res, err := c.statusG.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -168,10 +168,10 @@ func (wb *OpenWB20) CurrentPower() (float64, error) {
|
|||
return float64(int32(binary.BigEndian.Uint32(b))), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*OpenWB20)(nil)
|
||||
var _ api.MeterImport = (*OpenWB20)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *OpenWB20) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *OpenWB20) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegImport, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -164,10 +164,10 @@ func (wb *OpenWBPro) CurrentPower() (float64, error) {
|
|||
return res.PowerAll, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*OpenWBPro)(nil)
|
||||
var _ api.MeterImport = (*OpenWBPro)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *OpenWBPro) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *OpenWBPro) ImportEnergy() (float64, error) {
|
||||
res, err := wb.statusG.Get()
|
||||
return res.Imported / 1e3, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,10 +241,10 @@ func (m *OpenWB) CurrentPower() (float64, error) {
|
|||
return m.currentPowerG()
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*OpenWB)(nil)
|
||||
var _ api.MeterImport = (*OpenWB)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (m *OpenWB) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (m *OpenWB) ImportEnergy() (float64, error) {
|
||||
return m.totalEnergyG()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func NewPCElectricFromConfig(other map[string]any) (api.Charger, error) {
|
|||
var res pcelectric.MeterInfo
|
||||
if err := wb.GetJSON(wb.meter, &res); err == nil && res.MeterSerial != "" {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
return wb, nil
|
||||
}
|
||||
|
|
@ -248,7 +248,7 @@ func (wb *PCElectric) currentPower() (float64, error) {
|
|||
return 230 * (l1 + l2 + l3), err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface kwh
|
||||
// ImportEnergy implements the api.MeterImport interface kwh
|
||||
func (wb *PCElectric) totalEnergy() (float64, error) {
|
||||
var res pcelectric.MeterInfo
|
||||
uri := fmt.Sprintf("%s/meterinfo/%s", wb.uri, wb.meter)
|
||||
|
|
|
|||
|
|
@ -204,8 +204,8 @@ func (wb *Peblar) CurrentPower() (float64, error) {
|
|||
// deliberately removed, see https://github.com/evcc-io/evcc/issues/25956
|
||||
// var _ api.ChargeRater = (*Peblar)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Peblar) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Peblar) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(peblarRegEnergyTotal, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ func NewPhoenixCharxFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
|
||||
if meter > 0 && meter != 65535 {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
|
@ -229,7 +229,7 @@ func (wb *PhoenixCharx) currentPower() (float64, error) {
|
|||
return float64(encoding.Int32(b)) / 1e3, nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *PhoenixCharx) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wb.register(charxRegEnergy), 4)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func NewPhoenixEMEthFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
// check presence of meter by voltage on l1
|
||||
if b, err := wb.conn.ReadInputRegisters(phxEMEthRegVoltages, 2); err == nil && encoding.Int32LswFirst(b) > 0 {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ func (wb *PhoenixEMEth) currentPower() (float64, error) {
|
|||
return float64(encoding.Int32LswFirst(b)*1e3) * phxEMEthSF, nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *PhoenixEMEth) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(phxEMEthRegEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ func NewPhoenixEVEth(ctx context.Context, uri string, slaveID uint8) (api.Charge
|
|||
// check presence of meter by voltage on l1
|
||||
if b, err := wb.conn.ReadInputRegisters(phxRegVoltages, 2); err == nil && encoding.Uint32LswFirst(b) > 0 {
|
||||
implement.May(wb, implement.Meter(wb.currentPower))
|
||||
implement.May(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.May(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.May(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.May(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
|
@ -184,7 +184,7 @@ func (wb *PhoenixEVEth) currentPower() (float64, error) {
|
|||
return float64(encoding.Int32LswFirst(b)), nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *PhoenixEVEth) totalEnergy() (float64, error) {
|
||||
if wb.isWallbe {
|
||||
b, err := wb.conn.ReadHoldingRegisters(phxRegEnergyWallbe, 4)
|
||||
|
|
|
|||
|
|
@ -429,10 +429,10 @@ func (c *Pulsatrix) CurrentPower() (float64, error) {
|
|||
return res.LastActivePower, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Pulsatrix)(nil)
|
||||
var _ api.MeterImport = (*Pulsatrix)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *Pulsatrix) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *Pulsatrix) ImportEnergy() (float64, error) {
|
||||
res, err := c.data.Get()
|
||||
return res.EnergyImported, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,10 +191,10 @@ func (wb *Schneider) CurrentPower() (float64, error) {
|
|||
return float64(encoding.Float32LswFirst(b)) * 1e3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Schneider)(nil)
|
||||
var _ api.MeterImport = (*Schneider)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Schneider) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Schneider) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(schneiderRegEnergy, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -61,12 +61,12 @@ func NewSgReadyRelayFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
return nil, err
|
||||
}
|
||||
|
||||
powerG, energyG, err := cc.Energy.Configure(ctx)
|
||||
powerG, importG, _, err := cc.Energy.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
implement.May(res, implement.MeterImport(importG))
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -107,12 +107,12 @@ func NewSgReadyFromConfig(ctx context.Context, other map[string]any) (api.Charge
|
|||
return nil, err
|
||||
}
|
||||
|
||||
powerG, energyG, err := cc.Energy.Configure(ctx)
|
||||
powerG, importG, _, err := cc.Energy.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
implement.May(res, implement.MeterImport(importG))
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -183,10 +183,10 @@ func (c *ShellyTopAC) CurrentPower() (float64, error) {
|
|||
return phase.TotalPower * 1e3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*ShellyTopAC)(nil)
|
||||
var _ api.MeterImport = (*ShellyTopAC)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *ShellyTopAC) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *ShellyTopAC) ImportEnergy() (float64, error) {
|
||||
res, err := c.phaseG.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -93,9 +93,9 @@ func (c *Shelly) Enable(enable bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Shelly)(nil)
|
||||
var _ api.MeterImport = (*Shelly)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *Shelly) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *Shelly) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@ func (wb *Sigenergy) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Sigenergy)(nil)
|
||||
var _ api.MeterImport = (*Sigenergy)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Sigenergy) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Sigenergy) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(regSigTotalEnergyConsumed, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -242,10 +242,10 @@ func (wb *Smaevcharger) MaxCurrentMillis(current float64) error {
|
|||
return wb.Send(value("Parameter.Inverter.AcALim", fmt.Sprintf("%.2f", current)))
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Smaevcharger)(nil)
|
||||
var _ api.MeterImport = (*Smaevcharger)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Smaevcharger) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Smaevcharger) ImportEnergy() (float64, error) {
|
||||
res, err := wb.getMeasurement("Measurement.Metering.GridMs.TotWhIn")
|
||||
if _, ok := errors.AsType[*smaevcharger.ErrUnknownMeasurement](err); ok {
|
||||
res, err = wb.getMeasurement("Measurement.Metering.GridMs.TotWhIn.ChaSta")
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ func NewSmartEVSE3(uri string, cache time.Duration, mode int) (api.Charger, erro
|
|||
// decorate optional EV meter if configured in SmartEVSE
|
||||
if res.EvMeter.Description != "" && res.EvMeter.Description != "Disabled" {
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ func (wb *SmartEVSE3) currentPower() (float64, error) {
|
|||
return res.EvMeter.ImportActivePower, nil
|
||||
}
|
||||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
// totalEnergy implements the api.MeterImport interface
|
||||
func (wb *SmartEVSE3) totalEnergy() (float64, error) {
|
||||
res, err := wb.apiG.Get()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -174,10 +174,10 @@ func (wb *smartEVSE) CurrentPower() (float64, error) {
|
|||
return v1*i1 + v2*i2 + v3*i3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*smartEVSE)(nil)
|
||||
var _ api.MeterImport = (*smartEVSE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *smartEVSE) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *smartEVSE) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(smartEVSERegEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -225,10 +225,10 @@ func (wb *Solax) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint16(b)), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Solax)(nil)
|
||||
var _ api.MeterImport = (*Solax)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Solax) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Solax) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(solaxRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -240,10 +240,10 @@ func (wb *Sungrow) Voltages() (float64, float64, float64, error) {
|
|||
return wb.getPhaseValues(sgRegVoltages, 10)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Sungrow)(nil)
|
||||
var _ api.MeterImport = (*Sungrow)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Sungrow) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Sungrow) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(sgRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ func NewSwitchSocketFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.MeterEnergy(energy))
|
||||
implement.May(c, implement.MeterImport(energy))
|
||||
|
||||
soc, err := cc.Soc.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -92,11 +92,11 @@ func (c *Tasmota) Enable(enable bool) error {
|
|||
return c.conn.Enable(enable)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Tasmota)(nil)
|
||||
var _ api.MeterImport = (*Tasmota)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *Tasmota) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *Tasmota) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
||||
// Currents implements the api.PhaseCurrents interface
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ func (c *TPLink) Enable(enable bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*TPLink)(nil)
|
||||
var _ api.MeterImport = (*TPLink)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *TPLink) TotalEnergy() (float64, error) {
|
||||
return c.conn.TotalEnergy()
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (c *TPLink) ImportEnergy() (float64, error) {
|
||||
return c.conn.ImportEnergy()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,10 +167,10 @@ func (wb *Versicharge) CurrentPower() (float64, error) {
|
|||
return sum, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Versicharge)(nil)
|
||||
var _ api.MeterImport = (*Versicharge)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Versicharge) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Versicharge) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(versiRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -250,10 +250,10 @@ func (wb *Vestel) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Vestel)(nil)
|
||||
var _ api.MeterImport = (*Vestel)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Vestel) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Vestel) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadInputRegisters(vestelRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ func (wb *Victron) CurrentPower() (float64, error) {
|
|||
|
||||
var _ api.ChargeRater = (*Victron)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.MeterEnergy interface
|
||||
// ChargedEnergy implements the api.MeterImport interface
|
||||
func (wb *Victron) ChargedEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wb.regs.Energy, 1+cast.ToUint16(wb.regs.isGX))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
// Feature: Meter -> Meter is legacy API, Meters is the new API
|
||||
if w.hasFeature(warp.FeatureMeter) || w.hasFeature(warp.FeatureMeters) {
|
||||
implement.Has(w, implement.Meter(w.currentPower))
|
||||
implement.Has(w, implement.MeterEnergy(w.totalEnergy))
|
||||
implement.Has(w, implement.MeterImport(w.totalEnergy))
|
||||
}
|
||||
|
||||
// Feature: Meters | MeterAllValues
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ func NewWarp2FromConfig(other map[string]any) (api.Charger, error) {
|
|||
|
||||
if wb.hasFeature(cc.Topic, warp.FeatureMeter, cc.Timeout) {
|
||||
implement.May(wb, implement.Meter(wb.currentPower))
|
||||
implement.May(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.May(wb, implement.MeterImport(wb.totalEnergy))
|
||||
}
|
||||
|
||||
if wb.hasFeature(cc.Topic, warp.FeatureMeterPhases, cc.Timeout) {
|
||||
|
|
@ -244,7 +244,7 @@ func (wb *Warp2) currentPower() (float64, error) {
|
|||
return res.Power, err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Warp2) totalEnergy() (float64, error) {
|
||||
var res warp.MeterValues
|
||||
err := wb.meterG(&res)
|
||||
|
|
|
|||
|
|
@ -210,10 +210,10 @@ func (wb *WebastoNext) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*WebastoNext)(nil)
|
||||
var _ api.MeterImport = (*WebastoNext)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *WebastoNext) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *WebastoNext) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(tqRegEnergyMeter, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ func NewWeidmüller(ctx context.Context, uri string, id uint8) (api.Charger, err
|
|||
|
||||
// check presence of energy meter
|
||||
if b, err := wb.conn.ReadHoldingRegisters(wmRegTotalEnergy, 2); err == nil && binary.BigEndian.Uint32(b) > 0 {
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.MeterImport(wb.totalEnergy))
|
||||
}
|
||||
|
||||
return wb, nil
|
||||
|
|
@ -218,7 +218,7 @@ func (wb *Weidmüller) CurrentPower() (float64, error) {
|
|||
return float64(encoding.Uint32LswFirst(b)) / 1e3, err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *Weidmüller) totalEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wmRegTotalEnergy, 2)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -85,9 +85,16 @@ func (d *dumper) Dump(name string, v any) {
|
|||
})
|
||||
}
|
||||
|
||||
if v, ok := api.Cap[api.MeterEnergy](v); ok {
|
||||
d.measureTime(w, "Energy", func() (string, error) {
|
||||
energy, err := v.TotalEnergy()
|
||||
if v, ok := api.Cap[api.MeterImport](v); ok {
|
||||
d.measureTime(w, "Import", func() (string, error) {
|
||||
energy, err := v.ImportEnergy()
|
||||
return fmt.Sprintf("%.1fkWh", energy), err
|
||||
})
|
||||
}
|
||||
|
||||
if v, ok := api.Cap[api.MeterExport](v); ok {
|
||||
d.measureTime(w, "Export", func() (string, error) {
|
||||
energy, err := v.ExportEnergy()
|
||||
return fmt.Sprintf("%.1fkWh", energy), err
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ func generate(out io.Writer) error {
|
|||
reflect.TypeFor[api.PhaseSwitcher](),
|
||||
reflect.TypeFor[api.Battery](),
|
||||
reflect.TypeFor[api.ChargeState](),
|
||||
reflect.TypeFor[api.MeterEnergy](),
|
||||
reflect.TypeFor[api.MeterImport](),
|
||||
reflect.TypeFor[api.MeterExport](),
|
||||
reflect.TypeFor[api.PhaseCurrents](),
|
||||
reflect.TypeFor[api.PhaseVoltages](),
|
||||
reflect.TypeFor[api.MaxACPowerGetter](),
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ func (c *charger) Capacity() float64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*charger)(nil)
|
||||
var _ api.MeterImport = (*charger)(nil)
|
||||
|
||||
func (c *charger) TotalEnergy() (float64, error) {
|
||||
func (c *charger) ImportEnergy() (float64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ func TestCapsWrapping(t *testing.T) {
|
|||
assert.True(t, ok)
|
||||
}
|
||||
{
|
||||
_, ok := c.(api.MeterEnergy)
|
||||
_, ok := c.(api.MeterImport)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
{
|
||||
|
|
@ -89,14 +89,14 @@ func TestCapsWrapping(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
_, ok := m.(api.MeterEnergy)
|
||||
_, ok := m.(api.MeterImport)
|
||||
assert.False(t, ok, "unexpected promoted energy")
|
||||
assert.True(t, api.HasCap[api.MeterEnergy](m), "missing promoted energy cap")
|
||||
assert.True(t, api.HasCap[api.MeterImport](m), "missing promoted energy cap")
|
||||
|
||||
var mm any = m.(*capableMeter).Meter
|
||||
_, ok = mm.(api.MeterEnergy)
|
||||
_, ok = mm.(api.MeterImport)
|
||||
assert.True(t, ok, "missing embedded energy")
|
||||
assert.True(t, api.HasCap[api.MeterEnergy](mm), "missing embedded energy cap")
|
||||
assert.True(t, api.HasCap[api.MeterImport](mm), "missing embedded energy cap")
|
||||
}
|
||||
{
|
||||
_, ok := m.(api.Battery)
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ func (lp *Loadpoint) requestUpdate() {
|
|||
}
|
||||
|
||||
// capableMeter wraps a meter with capability lookup from its source.
|
||||
// This preserves capability checks (like MeterEnergy, PhaseCurrents, PhaseVoltages) when
|
||||
// This preserves capability checks (like MeterImport, MeterExport, PhaseCurrents, PhaseVoltages) when
|
||||
// the meter was extracted from a decorated charger's capability registry.
|
||||
type capableMeter struct {
|
||||
api.Meter
|
||||
|
|
@ -420,7 +420,7 @@ func (lp *Loadpoint) configureChargerType(charger api.Charger) {
|
|||
|
||||
if mt, ok := api.Cap[api.Meter](charger); ok {
|
||||
// preserve charger's capability registry so that subsequent
|
||||
// capability checks on chargeMeter (e.g. MeterEnergy, PhaseCurrents)
|
||||
// capability checks on chargeMeter (e.g. MeterImport, PhaseCurrents)
|
||||
// still work for decorated chargers (https://github.com/evcc-io/evcc/issues/28915)
|
||||
if c, ok := charger.(api.Capable); ok {
|
||||
lp.chargeMeter = &capableMeter{Meter: mt, Capable: c}
|
||||
|
|
@ -1743,7 +1743,7 @@ func (lp *Loadpoint) publishChargeProgress() {
|
|||
|
||||
// update energy, prefer totals
|
||||
var importTotal *float64
|
||||
if api.HasCap[api.MeterEnergy](lp.chargeMeter) {
|
||||
if api.HasCap[api.MeterImport](lp.chargeMeter) {
|
||||
if f := lp.chargeMeterTotal(); f > 0 {
|
||||
lp.publish(keys.ChargeTotalImport, f)
|
||||
importTotal = &f
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ import (
|
|||
)
|
||||
|
||||
func (lp *Loadpoint) chargeMeterTotal() float64 {
|
||||
m, ok := api.Cap[api.MeterEnergy](lp.chargeMeter)
|
||||
m, ok := api.Cap[api.MeterImport](lp.chargeMeter)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
f, err := m.TotalEnergy()
|
||||
f, err := m.ImportEnergy()
|
||||
if err != nil {
|
||||
if !errors.Is(err, api.ErrNotAvailable) {
|
||||
lp.log.ERROR.Printf("charge total import: %v", err)
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ func TestSession(t *testing.T) {
|
|||
defer ctrl.Finish()
|
||||
|
||||
mm := api.NewMockMeter(ctrl)
|
||||
me := api.NewMockMeterEnergy(ctrl)
|
||||
me := api.NewMockMeterImport(ctrl)
|
||||
|
||||
type EnergyDecorator struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.MeterImport
|
||||
}
|
||||
|
||||
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
|
||||
cm := &EnergyDecorator{Meter: mm, MeterImport: me}
|
||||
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
|
|
@ -53,7 +53,7 @@ func TestSession(t *testing.T) {
|
|||
}
|
||||
|
||||
// create session
|
||||
me.EXPECT().TotalEnergy().Return(1.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(1.0, nil)
|
||||
lp.createSession()
|
||||
assert.NotNil(t, lp.session)
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ func TestSession(t *testing.T) {
|
|||
// stop charging
|
||||
clock.Add(time.Hour)
|
||||
lp.energyMetrics.Update(1.23)
|
||||
me.EXPECT().TotalEnergy().Return(1.0+lp.getChargedEnergy()/1e3, nil) // match chargedEnergy
|
||||
me.EXPECT().ImportEnergy().Return(1.0+lp.getChargedEnergy()/1e3, nil) // match chargedEnergy
|
||||
|
||||
lp.stopSession()
|
||||
assert.NotNil(t, lp.session)
|
||||
|
|
@ -79,7 +79,7 @@ func TestSession(t *testing.T) {
|
|||
// stop charging - 2nd leg
|
||||
clock.Add(time.Hour)
|
||||
lp.energyMetrics.Update(lp.getChargedEnergy() * 2)
|
||||
me.EXPECT().TotalEnergy().Return(3.0, nil) // doesn't match chargedEnergy
|
||||
me.EXPECT().ImportEnergy().Return(3.0, nil) // doesn't match chargedEnergy
|
||||
|
||||
lp.stopSession()
|
||||
assert.NotNil(t, lp.session)
|
||||
|
|
@ -213,14 +213,14 @@ func TestResetHeatingSession(t *testing.T) {
|
|||
})
|
||||
|
||||
mm := api.NewMockMeter(ctrl)
|
||||
me := api.NewMockMeterEnergy(ctrl)
|
||||
me := api.NewMockMeterImport(ctrl)
|
||||
|
||||
type EnergyDecorator struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.MeterImport
|
||||
}
|
||||
|
||||
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
|
||||
cm := &EnergyDecorator{Meter: mm, MeterImport: me}
|
||||
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
|
|
@ -231,7 +231,7 @@ func TestResetHeatingSession(t *testing.T) {
|
|||
}
|
||||
|
||||
// create session
|
||||
me.EXPECT().TotalEnergy().Return(1.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(1.0, nil)
|
||||
lp.createSession()
|
||||
require.NotNil(t, lp.session)
|
||||
assert.True(t, lp.session.Created.IsZero())
|
||||
|
|
@ -241,7 +241,7 @@ func TestResetHeatingSession(t *testing.T) {
|
|||
assert.Equal(t, clock.Now(), lp.session.Created)
|
||||
|
||||
clock.Add(36 * time.Hour)
|
||||
me.EXPECT().TotalEnergy().Return(1.0, nil).MaxTimes(2)
|
||||
me.EXPECT().ImportEnergy().Return(1.0, nil).MaxTimes(2)
|
||||
|
||||
lp.resetHeatingSession()
|
||||
require.NotNil(t, lp.session)
|
||||
|
|
@ -250,7 +250,7 @@ func TestResetHeatingSession(t *testing.T) {
|
|||
lp.updateSession(sessionStart(lp))
|
||||
assert.Equal(t, clock.Now(), lp.session.Created)
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(3.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(3.0, nil)
|
||||
lp.stopSession()
|
||||
|
||||
assert.NotNil(t, lp.session)
|
||||
|
|
@ -260,7 +260,7 @@ func TestResetHeatingSession(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFinalizeSessionEnergy(t *testing.T) {
|
||||
setup := func(t *testing.T) (*Loadpoint, *api.MockMeterEnergy, *api.MockChargeRater) {
|
||||
setup := func(t *testing.T) (*Loadpoint, *api.MockMeterImport, *api.MockChargeRater) {
|
||||
t.Helper()
|
||||
var err error
|
||||
serverdb.Instance, err = serverdb.New("sqlite", ":memory:")
|
||||
|
|
@ -270,17 +270,17 @@ func TestFinalizeSessionEnergy(t *testing.T) {
|
|||
|
||||
ctrl := gomock.NewController(t)
|
||||
mm := api.NewMockMeter(ctrl)
|
||||
me := api.NewMockMeterEnergy(ctrl)
|
||||
me := api.NewMockMeterImport(ctrl)
|
||||
rater := api.NewMockChargeRater(ctrl)
|
||||
|
||||
type EnergyDecorator struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.MeterImport
|
||||
}
|
||||
|
||||
cm := &EnergyDecorator{
|
||||
Meter: mm,
|
||||
MeterEnergy: me,
|
||||
MeterImport: me,
|
||||
}
|
||||
|
||||
lp := &Loadpoint{
|
||||
|
|
@ -296,17 +296,17 @@ func TestFinalizeSessionEnergy(t *testing.T) {
|
|||
t.Run("corrects session when ChargedEnergy increased", func(t *testing.T) {
|
||||
lp, me, rater := setup(t)
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(9157.3, nil)
|
||||
me.EXPECT().ImportEnergy().Return(9157.3, nil)
|
||||
lp.createSession()
|
||||
lp.session.Created = lp.clock.Now()
|
||||
|
||||
lp.energyMetrics.Update(15.3)
|
||||
me.EXPECT().TotalEnergy().Return(9164.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(9164.0, nil)
|
||||
lp.stopSession()
|
||||
require.Equal(t, 15.3, lp.session.ChargedEnergy)
|
||||
|
||||
rater.EXPECT().ChargedEnergy().Return(16.2, nil)
|
||||
me.EXPECT().TotalEnergy().Return(9173.5, nil)
|
||||
me.EXPECT().ImportEnergy().Return(9173.5, nil)
|
||||
lp.finalizeSessionEnergy()
|
||||
|
||||
assert.Equal(t, 16.2, lp.session.ChargedEnergy)
|
||||
|
|
@ -317,12 +317,12 @@ func TestFinalizeSessionEnergy(t *testing.T) {
|
|||
t.Run("no-op when ChargedEnergy unchanged", func(t *testing.T) {
|
||||
lp, me, rater := setup(t)
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(9154.4, nil)
|
||||
me.EXPECT().ImportEnergy().Return(9154.4, nil)
|
||||
lp.createSession()
|
||||
lp.session.Created = lp.clock.Now()
|
||||
|
||||
lp.energyMetrics.Update(15.3)
|
||||
me.EXPECT().TotalEnergy().Return(9164.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(9164.0, nil)
|
||||
lp.stopSession()
|
||||
require.Equal(t, 15.3, lp.session.ChargedEnergy)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMeterEnergyMeterTotal(t *testing.T) {
|
||||
func TestMeterImportMeterTotal(t *testing.T) {
|
||||
clock := clock.NewMock()
|
||||
clock.Set(now.BeginningOfDay())
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ func TestMeterEnergyMeterTotal(t *testing.T) {
|
|||
assert.Equal(t, 1.0, me.Imported())
|
||||
}
|
||||
|
||||
func TestMeterEnergyAddPower(t *testing.T) {
|
||||
func TestMeterImportAddPower(t *testing.T) {
|
||||
clock := clock.NewMock()
|
||||
clock.Set(now.BeginningOfDay())
|
||||
|
||||
|
|
|
|||
23
core/site.go
23
core/site.go
|
|
@ -370,7 +370,7 @@ func meterCapabilities(name string, meter any) string {
|
|||
panic("not a meter: " + name)
|
||||
}
|
||||
|
||||
energy := api.HasCap[api.MeterEnergy](meter)
|
||||
energy := api.HasCap[api.MeterImport](meter) || api.HasCap[api.MeterExport](meter)
|
||||
currents := api.HasCap[api.PhaseCurrents](meter)
|
||||
|
||||
name += ":"
|
||||
|
|
@ -455,7 +455,7 @@ func (site *Site) DumpConfig() {
|
|||
lp.log.INFO.Printf(" mode: %s", lp.GetMode())
|
||||
|
||||
_, power := api.Cap[api.Meter](lp.charger)
|
||||
_, energy := api.Cap[api.MeterEnergy](lp.charger)
|
||||
_, energy := api.Cap[api.MeterImport](lp.charger)
|
||||
_, currents := api.Cap[api.PhaseCurrents](lp.charger)
|
||||
_, phases := api.Cap[api.PhaseSwitcher](lp.charger)
|
||||
_, wakeup := api.Cap[api.Resurrector](lp.charger)
|
||||
|
|
@ -516,10 +516,19 @@ func (site *Site) collectMeters(key string, meters []config.Device[api.Meter]) [
|
|||
site.log.ERROR.Printf("%s %d power: %v", key, i+1, err)
|
||||
}
|
||||
|
||||
// energy (production)
|
||||
// energy (production for pv/battery, consumption for aux/ext)
|
||||
var energy float64
|
||||
if m, ok := api.Cap[api.MeterEnergy](meter); err == nil && ok {
|
||||
energy, err = m.TotalEnergy()
|
||||
if err == nil {
|
||||
switch key {
|
||||
case "pv", "battery":
|
||||
if m, ok := api.Cap[api.MeterExport](meter); ok {
|
||||
energy, err = m.ExportEnergy()
|
||||
}
|
||||
default:
|
||||
if m, ok := api.Cap[api.MeterImport](meter); ok {
|
||||
energy, err = m.ImportEnergy()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
site.log.ERROR.Printf("%s %d energy: %v", key, i+1, err)
|
||||
}
|
||||
|
|
@ -786,8 +795,8 @@ func (site *Site) updateGridMeter() error {
|
|||
|
||||
// grid energy (import)
|
||||
var importEnergy *float64
|
||||
if energyMeter, ok := api.Cap[api.MeterEnergy](site.gridMeter); ok {
|
||||
if f, err := energyMeter.TotalEnergy(); err == nil {
|
||||
if energyMeter, ok := api.Cap[api.MeterImport](site.gridMeter); ok {
|
||||
if f, err := energyMeter.ImportEnergy(); err == nil {
|
||||
mm.Energy = f
|
||||
importEnergy = &f
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
// ChargeRater is responsible for providing charged energy amount
|
||||
// by implementing api.ChargeRater. It uses the charge meter's TotalEnergy or
|
||||
// by implementing api.ChargeRater. It uses the charge meter's ImportEnergy or
|
||||
// keeps track of consumed energy by regularly updating consumed power.
|
||||
type ChargeRater struct {
|
||||
sync.Mutex
|
||||
|
|
@ -39,19 +39,19 @@ func NewChargeRater(log *util.Logger, meter api.Meter) *ChargeRater {
|
|||
}
|
||||
}
|
||||
|
||||
// StartCharge records meter start energy. If meter does not supply TotalEnergy,
|
||||
// StartCharge records meter start energy. If meter does not supply ImportEnergy,
|
||||
// start time is recorded and charged energy set to zero.
|
||||
func (cr *ChargeRater) StartCharge(continued bool) {
|
||||
cr.Lock()
|
||||
defer cr.Unlock()
|
||||
|
||||
// time is needed if MeterEnergy is not supported
|
||||
// time is needed if MeterImport is not supported
|
||||
cr.start = cr.clck.Now()
|
||||
cr.startEnergy = nil
|
||||
|
||||
// get end energy amount
|
||||
if m, ok := api.Cap[api.MeterEnergy](cr.meter); ok {
|
||||
if f, err := m.TotalEnergy(); err == nil {
|
||||
if m, ok := api.Cap[api.MeterImport](cr.meter); ok {
|
||||
if f, err := m.ImportEnergy(); err == nil {
|
||||
cr.startEnergy = &f
|
||||
cr.log.DEBUG.Printf("charge start energy: %.3fkWh", f)
|
||||
} else if !loadpoint.AcceptableError(err) {
|
||||
|
|
@ -66,7 +66,7 @@ func (cr *ChargeRater) StartCharge(continued bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// StopCharge records meter stop energy. If meter does not supply TotalEnergy,
|
||||
// StopCharge records meter stop energy. If meter does not supply ImportEnergy,
|
||||
// stop time is recorded and accumulating energy though SetChargePower stopped.
|
||||
func (cr *ChargeRater) StopCharge() {
|
||||
cr.Lock()
|
||||
|
|
@ -75,8 +75,8 @@ func (cr *ChargeRater) StopCharge() {
|
|||
cr.charging = false
|
||||
|
||||
// get end energy amount
|
||||
if m, ok := api.Cap[api.MeterEnergy](cr.meter); ok {
|
||||
if f, err := m.TotalEnergy(); err == nil {
|
||||
if m, ok := api.Cap[api.MeterImport](cr.meter); ok {
|
||||
if f, err := m.ImportEnergy(); err == nil {
|
||||
if cr.startEnergy != nil {
|
||||
cr.chargedEnergy += f - *cr.startEnergy
|
||||
}
|
||||
|
|
@ -95,8 +95,8 @@ func (cr *ChargeRater) ResetCharge() {
|
|||
defer cr.Unlock()
|
||||
|
||||
// get end energy amount
|
||||
if m, ok := api.Cap[api.MeterEnergy](cr.meter); ok {
|
||||
if f, err := m.TotalEnergy(); err == nil {
|
||||
if m, ok := api.Cap[api.MeterImport](cr.meter); ok {
|
||||
if f, err := m.ImportEnergy(); err == nil {
|
||||
if cr.startEnergy != nil {
|
||||
cr.chargedEnergy += f - *cr.startEnergy
|
||||
cr.log.DEBUG.Printf("charge final energy: %.3fkWh", cr.chargedEnergy)
|
||||
|
|
@ -122,7 +122,7 @@ func (cr *ChargeRater) SetChargePower(power float64) {
|
|||
}
|
||||
|
||||
// update energy amount if not provided by meter
|
||||
if !api.HasCap[api.MeterEnergy](cr.meter) {
|
||||
if !api.HasCap[api.MeterImport](cr.meter) {
|
||||
// convert power to energy in kWh
|
||||
cr.chargedEnergy += power / 1e3 * float64(cr.clck.Since(cr.start)) / float64(time.Hour)
|
||||
// move timestamp
|
||||
|
|
@ -142,13 +142,13 @@ func (cr *ChargeRater) ChargedEnergy() (float64, error) {
|
|||
}
|
||||
|
||||
// get current energy amount
|
||||
if m, ok := api.Cap[api.MeterEnergy](cr.meter); ok {
|
||||
f, err := m.TotalEnergy()
|
||||
if m, ok := api.Cap[api.MeterImport](cr.meter); ok {
|
||||
f, err := m.ImportEnergy()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("charge total import: %v", err)
|
||||
}
|
||||
|
||||
// late-latch baseline if StartCharge could not read TotalEnergy
|
||||
// late-latch baseline if StartCharge could not read ImportEnergy
|
||||
// (e.g. OCPP transaction recovery before first MeterValues frame)
|
||||
if cr.startEnergy == nil {
|
||||
cr.startEnergy = &f
|
||||
|
|
|
|||
|
|
@ -62,20 +62,20 @@ func TestWrappedMeter(t *testing.T) {
|
|||
defer ctrl.Finish()
|
||||
|
||||
mm := api.NewMockMeter(ctrl)
|
||||
me := api.NewMockMeterEnergy(ctrl)
|
||||
me := api.NewMockMeterImport(ctrl)
|
||||
|
||||
type EnergyDecorator struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.MeterImport
|
||||
}
|
||||
|
||||
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
|
||||
cm := &EnergyDecorator{Meter: mm, MeterImport: me}
|
||||
|
||||
cr := NewChargeRater(util.NewLogger("foo"), cm)
|
||||
clck := clock.NewMock()
|
||||
cr.clck = clck
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(2.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(2.0, nil)
|
||||
|
||||
cr.StartCharge(false)
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ func TestWrappedMeter(t *testing.T) {
|
|||
clck.Add(time.Hour)
|
||||
cr.SetChargePower(0)
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(3.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(3.0, nil)
|
||||
|
||||
cr.StopCharge()
|
||||
|
||||
|
|
@ -98,12 +98,12 @@ func TestWrappedMeter(t *testing.T) {
|
|||
cr.SetChargePower(1e3)
|
||||
|
||||
// continue
|
||||
me.EXPECT().TotalEnergy().Return(10.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(10.0, nil)
|
||||
|
||||
cr.StartCharge(true)
|
||||
clck.Add(time.Hour) // actual timing ignored as energy comes from meter
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(12.0, nil)
|
||||
me.EXPECT().ImportEnergy().Return(12.0, nil)
|
||||
|
||||
cr.StopCharge()
|
||||
|
||||
|
|
@ -114,53 +114,53 @@ func TestWrappedMeter(t *testing.T) {
|
|||
|
||||
// TestDeferredBaseline covers the OCPP transaction-recovery case: the meter is
|
||||
// not yet readable when StartCharge fires, so the baseline must be latched on
|
||||
// the first successful TotalEnergy() read instead of defaulting to zero
|
||||
// the first successful ImportEnergy() read instead of defaulting to zero
|
||||
// (which would cause the lifetime register to be reported as session energy).
|
||||
func TestDeferredBaseline(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
mm := api.NewMockMeter(ctrl)
|
||||
me := api.NewMockMeterEnergy(ctrl)
|
||||
me := api.NewMockMeterImport(ctrl)
|
||||
|
||||
type EnergyDecorator struct {
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.MeterImport
|
||||
}
|
||||
|
||||
cm := &EnergyDecorator{Meter: mm, MeterEnergy: me}
|
||||
cm := &EnergyDecorator{Meter: mm, MeterImport: me}
|
||||
|
||||
cr := NewChargeRater(util.NewLogger("foo"), cm)
|
||||
clck := clock.NewMock()
|
||||
cr.clck = clck
|
||||
|
||||
// meter not yet available at StartCharge — recovered transaction before first MeterValues
|
||||
me.EXPECT().TotalEnergy().Return(0.0, errors.New("not available"))
|
||||
me.EXPECT().ImportEnergy().Return(0.0, errors.New("not available"))
|
||||
|
||||
cr.StartCharge(true)
|
||||
|
||||
// first read also fails — must surface the error, not a bogus delta
|
||||
me.EXPECT().TotalEnergy().Return(0.0, errors.New("not available"))
|
||||
me.EXPECT().ImportEnergy().Return(0.0, errors.New("not available"))
|
||||
|
||||
if _, err := cr.ChargedEnergy(); err == nil {
|
||||
t.Errorf("expected error while meter unavailable")
|
||||
}
|
||||
|
||||
// first successful read latches the baseline (lifetime register, e.g. 939 kWh)
|
||||
me.EXPECT().TotalEnergy().Return(939.080, nil)
|
||||
me.EXPECT().ImportEnergy().Return(939.080, nil)
|
||||
|
||||
if f, err := cr.ChargedEnergy(); f != 0 || err != nil {
|
||||
t.Errorf("expected 0 on baseline-latch read, got %.3f %v", f, err)
|
||||
}
|
||||
|
||||
// subsequent reads return delta against the latched baseline
|
||||
me.EXPECT().TotalEnergy().Return(942.080, nil)
|
||||
me.EXPECT().ImportEnergy().Return(942.080, nil)
|
||||
|
||||
if f, err := cr.ChargedEnergy(); f != 3 || err != nil {
|
||||
t.Errorf("expected 3kWh delta, got %.3f %v", f, err)
|
||||
}
|
||||
|
||||
me.EXPECT().TotalEnergy().Return(944.080, nil)
|
||||
me.EXPECT().ImportEnergy().Return(944.080, nil)
|
||||
|
||||
cr.StopCharge()
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ func (m *Blueprint) CurrentPower() (float64, error) {
|
|||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Blueprint)(nil)
|
||||
var _ api.MeterImport = (*Blueprint)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (m *Blueprint) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (m *Blueprint) ImportEnergy() (float64, error) {
|
||||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@ func (wb *CfosPowerBrain) CurrentPower() (float64, error) {
|
|||
return float64(binary.BigEndian.Uint32(b)), err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*CfosPowerBrain)(nil)
|
||||
var _ api.MeterImport = (*CfosPowerBrain)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *CfosPowerBrain) TotalEnergy() (float64, error) {
|
||||
// ImportEnergy implements the api.MeterImport interface
|
||||
func (wb *CfosPowerBrain) ImportEnergy() (float64, error) {
|
||||
b, err := wb.conn.ReadHoldingRegisters(cfosRegEnergy, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func NewDanfossTLX(ctx context.Context, cfg comlynx.Config, maxACPower func() fl
|
|||
}
|
||||
|
||||
if hasEnergy == nil {
|
||||
implement.Has(m, implement.MeterEnergy(m.totalEnergy))
|
||||
implement.Has(m, implement.MeterImport(m.totalEnergy))
|
||||
}
|
||||
if hasVoltages == nil {
|
||||
implement.Has(m, implement.PhaseVoltages(m.phaseVoltages))
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ func (m *Discovergy) CurrentPower() (float64, error) {
|
|||
return m.scale * float64(res.Values.Power) / 1e3, err
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*Discovergy)(nil)
|
||||
var _ api.MeterImport = (*Discovergy)(nil)
|
||||
|
||||
func (m *Discovergy) TotalEnergy() (float64, error) {
|
||||
func (m *Discovergy) ImportEnergy() (float64, error) {
|
||||
res, err := m.dataG()
|
||||
return float64(res.Values.Energy) / 1e10, err
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue