Move MaxACPower hybrid setting to pv config (#16735)

This commit is contained in:
andig 2024-10-19 17:11:07 +02:00 • committed by GitHub
parent 88b9a2b744
commit 5949829117
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 651 additions and 419 deletions

View file

@ -44,8 +44,8 @@ type BatteryCapacity interface {
Capacity() float64
}
// BatteryMaxACPower provides max AC power in W
type BatteryMaxACPower interface {
// MaxACPower provides max AC power in W
type MaxACPower interface {
MaxACPower() float64
}

View file

@ -120,7 +120,7 @@ func (d *dumper) Dump(name string, v interface{}) {
fmt.Fprintf(w, "Capacity:\t%.1fkWh\n", v.Capacity())
}
if v, ok := v.(api.BatteryMaxACPower); ok {
if v, ok := v.(api.MaxACPower); ok {
fmt.Fprintf(w, "Max AC power:\t%.0fW\n", v.MaxACPower())
}

View file

@ -40,13 +40,13 @@ var a struct {
api.PhaseCurrents
api.PhaseVoltages
api.PhasePowers
api.MaxACPower
api.PhaseSwitcher
api.PhaseGetter
api.Battery
api.BatteryCapacity
api.BatteryMaxACPower
api.BatteryController
}
@ -55,10 +55,10 @@ func typ(i any) string {
}
var dependents = map[string][]string{
typ(&a.Meter): {typ(&a.MeterEnergy), typ(&a.PhaseCurrents), typ(&a.PhaseVoltages), typ(&a.PhasePowers)},
typ(&a.Meter): {typ(&a.MeterEnergy), typ(&a.PhaseCurrents), typ(&a.PhaseVoltages), typ(&a.PhasePowers), typ(&a.MaxACPower)},
typ(&a.PhaseCurrents): {typ(&a.PhasePowers)}, // phase powers are only used to determine currents sign
typ(&a.PhaseSwitcher): {typ(&a.PhaseGetter)},
typ(&a.Battery): {typ(&a.BatteryCapacity), typ(&a.BatteryMaxACPower), typ(&a.BatteryController)},
typ(&a.Battery): {typ(&a.BatteryCapacity), typ(&a.BatteryController)},
}
// hasIntersection returns if the slices intersect

View file

@ -43,18 +43,18 @@ type updater interface {
// meterMeasurement is used as slice element for publishing structured data
type meterMeasurement struct {
Power float64 `json:"power"`
Energy float64 `json:"energy,omitempty"`
Power float64 `json:"power"`
Energy float64 `json:"energy,omitempty"`
ExcessDCPower float64 `json:"excessdcpower,omitempty"`
}
// batteryMeasurement is used as slice element for publishing structured data
type batteryMeasurement struct {
Power float64 `json:"power"`
ExcessDCPower float64 `json:"excessdcpower,omitempty"`
Energy float64 `json:"energy,omitempty"`
Soc float64 `json:"soc,omitempty"`
Capacity float64 `json:"capacity,omitempty"`
Controllable bool `json:"controllable"`
Power float64 `json:"power"`
Energy float64 `json:"energy,omitempty"`
Soc float64 `json:"soc,omitempty"`
Capacity float64 `json:"capacity,omitempty"`
Controllable bool `json:"controllable"`
}
var _ site.API = (*Site)(nil)
@ -100,13 +100,13 @@ type Site struct {
stats *Stats // Stats
// cached state
gridPower float64 // Grid power
pvPower float64 // PV power
auxPower float64 // Aux power
batteryPower float64 // Battery charge power
batteryExcessDC float64 // Battery excess DC charge power (hybrid only)
batterySoc float64 // Battery soc
batteryMode api.BatteryMode // Battery mode (runtime only, not persisted)
gridPower float64 // Grid power
pvPower float64 // PV power
excessDCPower float64 // PV excess DC charge power (hybrid only)
auxPower float64 // Aux power
batteryPower float64 // Battery charge power
batterySoc float64 // Battery soc
batteryMode api.BatteryMode // Battery mode (runtime only, not persisted)
publishCache map[string]any // store last published values to avoid unnecessary republishing
}
@ -229,7 +229,7 @@ func (site *Site) Boot(log *util.Logger, loadpoints []*Loadpoint, tariffs *tarif
}
if site.MaxGridSupplyWhileBatteryCharging_ != 0 {
site.log.WARN.Println("`MaxGridSupplyWhileBatteryCharging` is deprecated- use `maxACPower` in battery configuration instead")
site.log.WARN.Println("`MaxGridSupplyWhileBatteryCharging` is deprecated- use `maxACPower` in pv configuration instead")
}
// revert battery mode on shutdown
@ -476,9 +476,27 @@ func (site *Site) updatePvMeters() {
}
}
var excessDC float64
var excessStr string
if m, ok := meter.(api.MaxACPower); ok {
if dc := m.MaxACPower() - power; dc < 0 && power > 0 {
mu.Lock()
site.excessDCPower += dc
mu.Unlock()
excessDC = dc
excessStr = fmt.Sprintf(" (includes %.0fW excess DC)", dc)
}
}
if len(site.pvMeters) > 1 {
site.log.DEBUG.Printf("pv %d power: %.0fW"+excessStr, i+1, power)
}
mm[i] = meterMeasurement{
Power: power,
Energy: energy,
Power: power,
Energy: energy,
ExcessDCPower: excessDC,
}
wg.Done()
@ -563,7 +581,7 @@ func (site *Site) updateBatteryMeters() error {
var mu sync.Mutex
site.batteryPower = 0
site.batteryExcessDC = 0
site.excessDCPower = 0
site.batterySoc = 0
mm := make([]batteryMeasurement, len(site.batteryMeters))
@ -579,21 +597,8 @@ func (site *Site) updateBatteryMeters() error {
site.batteryPower += power
mu.Unlock()
var excessDC float64
var excessStr string
if m, ok := meter.(api.BatteryMaxACPower); ok {
if dc := power + m.MaxACPower(); dc < 0 {
mu.Lock()
site.batteryExcessDC += dc
mu.Unlock()
excessDC = dc
excessStr = fmt.Sprintf(" (includes %.0fW excess DC)", dc)
}
}
if len(site.batteryMeters) > 1 {
site.log.DEBUG.Printf("battery %d power: %.0fW"+excessStr, i+1, power)
site.log.DEBUG.Printf("battery %d power: %.0fW", i+1, power)
}
// battery energy (discharge)
@ -639,12 +644,11 @@ func (site *Site) updateBatteryMeters() error {
_, controllable := meter.(api.BatteryController)
mm[i] = batteryMeasurement{
Power: power,
ExcessDCPower: excessDC,
Energy: energy,
Soc: batSoc,
Capacity: capacity,
Controllable: controllable,
Power: power,
Energy: energy,
Soc: batSoc,
Capacity: capacity,
Controllable: controllable,
}
return nil
@ -670,8 +674,8 @@ func (site *Site) updateBatteryMeters() error {
site.publish(keys.BatterySoc, site.batterySoc)
var excessStr string
if site.batteryExcessDC > 0 {
excessStr = fmt.Sprintf(" (includes %.0fW excess DC)", site.batteryExcessDC)
if site.excessDCPower > 0 {
excessStr = fmt.Sprintf(" (includes %.0fW excess DC)", site.excessDCPower)
}
site.log.DEBUG.Printf("battery power: %.0fW"+excessStr, site.batteryPower)
@ -778,7 +782,7 @@ func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, b
// honour battery priority
batteryPower := site.batteryPower
batteryExcessDC := site.batteryExcessDC
excessDCPower := site.excessDCPower
// handed to loadpoint
var batteryBuffered, batteryStart bool
@ -791,7 +795,7 @@ func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, b
if site.batterySoc < site.prioritySoc && batteryPower < 0 {
site.log.DEBUG.Printf("battery has priority at soc %.0f%% (< %.0f%%)", site.batterySoc, site.prioritySoc)
batteryPower = 0
batteryExcessDC = 0
excessDCPower = 0
} else {
// if battery is above bufferSoc allow using it for charging
batteryBuffered = site.bufferSoc > 0 && site.batterySoc > site.bufferSoc
@ -799,7 +803,7 @@ func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, b
}
}
sitePower := site.gridPower + batteryPower - batteryExcessDC + residualPower - site.auxPower - flexiblePower
sitePower := site.gridPower + batteryPower - excessDCPower + residualPower - site.auxPower - flexiblePower
// handle priority
var flexStr string

View file

@ -13,7 +13,7 @@ func init() {
registry.AddCtx(api.Custom, NewConfigurableFromConfig)
}
//go:generate go run ../cmd/tools/decorate.go -f decorateMeter -b api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.PhasePowers,Powers,func() (float64, float64, float64, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatteryCapacity,Capacity,func() float64" -t "api.BatteryMaxACPower,MaxACPower,func() float64" -t "api.BatteryController,SetBatteryMode,func(api.BatteryMode) error"
//go:generate go run ../cmd/tools/decorate.go -f decorateMeter -b api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.PhasePowers,Powers,func() (float64, float64, float64, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatteryCapacity,Capacity,func() float64" -t "api.MaxACPower,MaxACPower,func() float64" -t "api.BatteryController,SetBatteryMode,func(api.BatteryMode) error"
// NewConfigurableFromConfig creates api.Meter from config
func NewConfigurableFromConfig(ctx context.Context, other map[string]interface{}) (api.Meter, error) {
@ -109,10 +109,10 @@ func (m *Meter) Decorate(
powers func() (float64, float64, float64, error),
batterySoc func() (float64, error),
batteryCapacity func() float64,
batteryMaxACPower func() float64,
MaxACPower func() float64,
setBatteryMode func(api.BatteryMode) error,
) api.Meter {
return decorateMeter(m, totalEnergy, currents, voltages, powers, batterySoc, batteryCapacity, batteryMaxACPower, setBatteryMode)
return decorateMeter(m, totalEnergy, currents, voltages, powers, batterySoc, batteryCapacity, MaxACPower, setBatteryMode)
}
// CurrentPower implements the api.Meter interface

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,7 @@ render: |
uri: {{ .host }}:{{ .port }}
id: 1
value: 160:2:DCW # mppt 2
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
type: custom
@ -165,5 +166,4 @@ render: |
id: 1
value: 124:0:InOutWRte_RvrtTms
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -75,6 +75,7 @@ render: |
type: holding
decode: uint32
scale: 0.1
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -175,5 +176,4 @@ render: |
type: writemultiple
encoding: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -83,6 +83,7 @@ render: |
type: input
decode: uint32
scale: 0.1
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -214,5 +215,4 @@ render: |
type: writemultiple
decode: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -72,6 +72,7 @@ render: |
type: input
decode: uint32
scale: 0.1
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -176,5 +177,4 @@ render: |
type: writemultiple
decode: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -59,6 +59,7 @@ render: |
{{- include "modbus" . | indent 2 }}
value: 103:WH # total yield
scale: 0.001
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
type: custom
@ -111,5 +112,4 @@ render: |
type: writemultiple
encoding: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -65,6 +65,7 @@ render: |
{{- include "modbus" . | indent 2 }}
value: 103:WH # total yield
scale: 0.001
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
type: custom
@ -87,7 +88,6 @@ render: |
type: writemultiple
encoding: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
minsoc: {{ .minsoc }} # %
maxsoc: {{ .maxsoc }} # %
{{- end }}

View file

@ -88,6 +88,7 @@ render: |
type: holding
decode: uint64nan
scale: 0.001
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -184,5 +185,4 @@ render: |
type: writemultiple
decode: uint32
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -114,6 +114,7 @@ render: |
address: 62836 # Battery 1 Instantaneous Power
type: holding
decode: float32nans
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -207,5 +208,4 @@ render: |
type: writemultiple
encoding: float32s
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -61,6 +61,7 @@ render: |
type: input
decode: uint32s
scale: 0.1
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
source: modbus
@ -136,5 +137,4 @@ render: |
type: writesingle
decode: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -93,6 +93,7 @@ render: |
address: 33029 # Total energy generation
type: input
decode: uint32
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -130,5 +131,4 @@ render: |
type: input
decode: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -93,6 +93,7 @@ render: |
address: 33029 # Total energy generation
type: input
decode: uint32
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -118,5 +119,4 @@ render: |
type: input
decode: uint16
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -101,6 +101,7 @@ render: |
{{- include "modbus" . | indent 6 }}
value: 160:2:DCWH # mppt 2
scale: 0.001
maxacpower: {{ .maxacpower }} # W
{{- end }}
{{- if eq .usage "battery" }}
power:
@ -125,5 +126,4 @@ render: |
- 124:ChaState
- 802:SoC
capacity: {{ .capacity }} # kWh
maxacpower: {{ .maxacpower }} # W
{{- end }}

View file

@ -105,7 +105,7 @@ params:
default: 0
example: 5000
type: float
usages: ["battery"]
usages: ["pv"]
advanced: true
- name: vin
description: