SMA: add battery params (BC) (#26899)

This commit is contained in:
andig 2026-01-22 19:04:30 +01:00 • committed by GitHub
parent 37bee0cde5
commit 7f812f8b71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 31 additions and 78 deletions

View file

@ -24,13 +24,14 @@ func init() {
registry.Add("sma", NewSMAFromConfig)
}
//go:generate go tool decorate -f decorateSMA -b *SMA -r api.Meter -t "api.Battery,Soc,func() (float64, error)" -t "api.BatteryCapacity,Capacity,func() float64"
// NewSMAFromConfig creates an SMA meter from generic config
func NewSMAFromConfig(other map[string]any) (api.Meter, error) {
cc := struct {
batteryCapacity `mapstructure:",squash"`
batteryPowerLimits `mapstructure:",squash"`
batterySocLimits `mapstructure:",squash"`
URI, Password, Interface string
Usage string
Serial uint32
Scale float64 // power only
}{
@ -42,11 +43,24 @@ func NewSMAFromConfig(other map[string]any) (api.Meter, error) {
return nil, err
}
return NewSMA(cc.URI, cc.Password, cc.Interface, cc.Serial, cc.Scale, cc.batteryCapacity.Decorator())
sm, err := NewSMA(cc.URI, cc.Password, cc.Interface, cc.Serial, cc.Scale)
if err != nil {
return nil, err
}
if cc.Usage == "battery" {
return decorateMeterBattery(
sm, sm.TotalEnergy,
sm.soc, cc.batteryCapacity.Decorator(),
cc.batterySocLimits.Decorator(), cc.batteryPowerLimits.Decorator(), nil,
), nil
}
return sm, nil
}
// NewSMA creates an SMA meter
func NewSMA(uri, password, iface string, serial uint32, scale float64, capacity func() float64) (api.Meter, error) {
func NewSMA(uri, password, iface string, serial uint32, scale float64) (*SMA, error) {
sm := &SMA{
uri: uri,
scale: scale,
@ -82,20 +96,7 @@ func NewSMA(uri, password, iface string, serial uint32, scale float64, capacity
// start update loop manually to get values as fast as possible
go sm.device.Run()
// decorate api.Battery in case of inverter
var soc func() (float64, error)
if !sm.device.IsEnergyMeter() {
vals, err := sm.device.Values()
if err != nil {
return nil, err
}
if _, ok := vals[sunny.BatteryCharge]; ok {
soc = sm.soc
}
}
return decorateSMA(sm, soc, capacity), nil
return sm, nil
}
// CurrentPower implements the api.Meter interface
@ -170,7 +171,14 @@ func (sm *SMA) Powers() (float64, float64, float64, error) {
// soc implements the api.Battery interface
func (sm *SMA) soc() (float64, error) {
values, err := sm.device.Values()
return sma.AsFloat(values[sunny.BatteryCharge]), err
if err != nil {
return 0, err
}
soc, ok := values[sunny.BatteryCharge]
if !ok {
return 0, api.ErrNotAvailable
}
return sma.AsFloat(soc), nil
}
var _ api.Diagnosis = (*SMA)(nil)

View file

@ -1,58 +0,0 @@
package meter
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
import (
"github.com/evcc-io/evcc/api"
)
func decorateSMA(base *SMA, battery func() (float64, error), batteryCapacity func() float64) api.Meter {
switch {
case battery == nil:
return base
case battery != nil && batteryCapacity == nil:
return &struct {
*SMA
api.Battery
}{
SMA: base,
Battery: &decorateSMABatteryImpl{
battery: battery,
},
}
case battery != nil && batteryCapacity != nil:
return &struct {
*SMA
api.Battery
api.BatteryCapacity
}{
SMA: base,
Battery: &decorateSMABatteryImpl{
battery: battery,
},
BatteryCapacity: &decorateSMABatteryCapacityImpl{
batteryCapacity: batteryCapacity,
},
}
}
return nil
}
type decorateSMABatteryImpl struct {
battery func() (float64, error)
}
func (impl *decorateSMABatteryImpl) Soc() (float64, error) {
return impl.battery()
}
type decorateSMABatteryCapacityImpl struct {
batteryCapacity func() float64
}
func (impl *decorateSMABatteryCapacityImpl) Capacity() float64 {
return impl.batteryCapacity()
}

View file

@ -39,6 +39,8 @@ type batterySocLimits struct {
MinSoc, MaxSoc float64
}
// var _ api.BatterySocLimiter = (*batterySocLimits)(nil)
// Decorator returns an api.BatterySocLimiter decorator
func (m *batterySocLimits) Decorator() func() (float64, float64) {
if m.MinSoc == 0 && m.MaxSoc == 0 {

View file

@ -27,7 +27,7 @@ render: |
id: {{ .id }}
register:
address: 2201 # SUR Überschussleistung Auflösung 1 W
type: writeholding
type: writesingle
decode: int16
power:
source: modbus

View file

@ -19,6 +19,7 @@ params:
- preset: battery-params
render: |
type: sma
usage: {{ .usage }}
uri: {{ .host }} # IP address or hostname
password: {{ .password }} # optional
{{- if eq .usage "battery" }}