Add SMA Sunny Home Manager 2.0 ModbusTCP with curtailment (#32091)
This commit is contained in:
parent
19ed27fa54
commit
0a98d57cec
3 changed files with 77 additions and 13 deletions
21
core/site.go
21
core/site.go
|
|
@ -69,7 +69,7 @@ type Site struct {
|
|||
// meters
|
||||
circuit api.Circuit // Circuit
|
||||
hems api.HEMS // HEMS (set by configureHEMS at boot)
|
||||
gridMeter api.Meter // Grid usage meter
|
||||
gridMeter config.Device[api.Meter] // Grid usage meter
|
||||
pvMeters []config.Device[api.Meter] // PV generation meters
|
||||
batteryMeters []config.Device[api.Meter] // Battery charging meters
|
||||
extMeters []config.Device[api.Meter] // External meters - for monitoring only
|
||||
|
|
@ -206,10 +206,7 @@ func (site *Site) Boot(log *util.Logger, loadpoints []*Loadpoint, tariffs *tarif
|
|||
return err
|
||||
}
|
||||
|
||||
site.gridMeter = dev.Instance()
|
||||
if site.gridMeter == nil {
|
||||
return errors.New("missing grid meter instance")
|
||||
}
|
||||
site.gridMeter = dev
|
||||
|
||||
me, err := metrics.NewCollector(metrics.Grid, site.Meters.GridMeterRef, metrics.Grid)
|
||||
if err != nil {
|
||||
|
|
@ -456,7 +453,7 @@ func (site *Site) DumpConfig() {
|
|||
)
|
||||
|
||||
if site.gridMeter != nil {
|
||||
site.log.INFO.Println(meterCapabilities("grid", site.gridMeter))
|
||||
site.log.INFO.Println(meterCapabilities("grid", site.gridMeter.Instance()))
|
||||
}
|
||||
|
||||
if len(site.pvMeters) > 0 {
|
||||
|
|
@ -864,7 +861,9 @@ func (site *Site) updateGridMeter() error {
|
|||
|
||||
mm := types.Measurement{Name: site.Meters.GridMeterRef}
|
||||
|
||||
if res, err := backoff.RetryWithData(site.gridMeter.CurrentPower, modbus.Backoff()); err == nil {
|
||||
meter := site.gridMeter.Instance()
|
||||
|
||||
if res, err := backoff.RetryWithData(meter.CurrentPower, modbus.Backoff()); err == nil {
|
||||
mm.Power = res
|
||||
site.gridPower = res
|
||||
site.log.DEBUG.Printf("grid power: %.0fW", res)
|
||||
|
|
@ -873,10 +872,10 @@ func (site *Site) updateGridMeter() error {
|
|||
}
|
||||
|
||||
// grid phase currents (signed)
|
||||
if phaseMeter, ok := api.Cap[api.PhaseCurrents](site.gridMeter); ok {
|
||||
if phaseMeter, ok := api.Cap[api.PhaseCurrents](meter); ok {
|
||||
// grid phase powers
|
||||
var p1, p2, p3 float64
|
||||
if phaseMeter, ok := api.Cap[api.PhasePowers](site.gridMeter); ok {
|
||||
if phaseMeter, ok := api.Cap[api.PhasePowers](meter); ok {
|
||||
var err error // phases needed for signed currents
|
||||
if p1, p2, p3, err = phaseMeter.Powers(); err == nil {
|
||||
mm.Powers = []float64{p1, p2, p3}
|
||||
|
|
@ -896,7 +895,7 @@ func (site *Site) updateGridMeter() error {
|
|||
|
||||
// grid energy (import); nil when the device has no MeterEnergy capability or the read fails
|
||||
// ignore spurious zero readings (NaN-derived or nightly reset, #30950)
|
||||
if energyMeter, ok := api.Cap[api.MeterEnergy](site.gridMeter); ok {
|
||||
if energyMeter, ok := api.Cap[api.MeterEnergy](meter); ok {
|
||||
if f, err := nonZeroEnergy(energyMeter.TotalEnergy()); err == nil {
|
||||
mm.Energy = &f
|
||||
} else if !errors.Is(err, api.ErrNotAvailable) {
|
||||
|
|
@ -906,7 +905,7 @@ func (site *Site) updateGridMeter() error {
|
|||
|
||||
// grid return energy (export); nil when the device has no MeterReturnEnergy capability or the read fails
|
||||
// ignore spurious zero readings as above
|
||||
if returnEnergyMeter, ok := api.Cap[api.MeterReturnEnergy](site.gridMeter); ok {
|
||||
if returnEnergyMeter, ok := api.Cap[api.MeterReturnEnergy](meter); ok {
|
||||
if f, err := nonZeroEnergy(returnEnergyMeter.ReturnEnergy()); err == nil {
|
||||
mm.ReturnEnergy = &f
|
||||
} else if !errors.Is(err, api.ErrNotAvailable) {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ func (site *Site) dimMeters(dim bool) error {
|
|||
return errs
|
||||
}
|
||||
|
||||
// curtailPV applies the HEMS curtailment percent to all curtailable pv meters.
|
||||
// curtailPV applies the HEMS curtailment percent to all curtailable pv or grid meters.
|
||||
// Devices are only queried when the percent changes or after a failed attempt.
|
||||
func (site *Site) curtailPV(percent *int) error {
|
||||
if percent == nil || site.curtailPercent != nil && *site.curtailPercent == *percent {
|
||||
|
|
@ -107,8 +107,13 @@ func (site *Site) curtailPV(percent *int) error {
|
|||
// invalidate until successfully applied
|
||||
site.curtailPercent = nil
|
||||
|
||||
meters := slices.Clone(site.pvMeters)
|
||||
if site.gridMeter != nil {
|
||||
meters = append(meters, site.gridMeter)
|
||||
}
|
||||
|
||||
var errs error
|
||||
for _, dev := range site.pvMeters {
|
||||
for _, dev := range meters {
|
||||
m, ok := api.Cap[api.Curtailer](dev.Instance())
|
||||
if !ok {
|
||||
continue
|
||||
|
|
|
|||
60
templates/definition/meter/sma-homemanager-modbus.yaml
Normal file
60
templates/definition/meter/sma-homemanager-modbus.yaml
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
template: sma-homemanager-modbus
|
||||
products:
|
||||
- brand: SMA
|
||||
description:
|
||||
generic: Sunny Home Manager 2.0 Modbus
|
||||
capabilities: ["curtail"]
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["grid"]
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
port: 502
|
||||
id: 2
|
||||
help:
|
||||
en: ModbusTCP server needs to be enabled.
|
||||
de: Der ModbusTCP Server muss aktiviert sein.
|
||||
render: |
|
||||
type: custom
|
||||
power:
|
||||
source: calc
|
||||
add:
|
||||
- source: modbus
|
||||
{{- include "modbus" . | indent 6 }}
|
||||
register:
|
||||
address: 30865 # SMA Modbus Profile: Metering.GridMs.TotWIn
|
||||
type: input
|
||||
decode: int32nan
|
||||
- source: modbus
|
||||
{{- include "modbus" . | indent 6 }}
|
||||
register:
|
||||
address: 30867 # SMA Modbus Profile: Metering.GridMs.TotWOut
|
||||
type: input
|
||||
decode: int32nan
|
||||
scale: -1
|
||||
energy:
|
||||
source: modbus
|
||||
{{- include "modbus" . | indent 2 }}
|
||||
register:
|
||||
address: 30581 # SMA Modbus Profile: Metering.GridMs.TotWhIn
|
||||
type: holding
|
||||
decode: int32nan
|
||||
scale: 0.001
|
||||
returnenergy:
|
||||
source: modbus
|
||||
{{- include "modbus" . | indent 2 }}
|
||||
register:
|
||||
address: 30583 # SMA Modbus Profile: Metering.GridMs.TotWhOut
|
||||
type: holding
|
||||
decode: int32nan
|
||||
scale: 0.001
|
||||
curtail:
|
||||
source: modbus
|
||||
{{- include "modbus" . | indent 2 }}
|
||||
register:
|
||||
address: 40016 # Wirkleistungssollwert P, in % der maximalen Wirkleistung (PMAX) der PV-Anlage.
|
||||
type: writesingle
|
||||
decode: uint16
|
||||
curtailed:
|
||||
source: error
|
||||
error: ErrNotAvailable
|
||||
Loading…
Add table
Add a link
Reference in a new issue