Move MaxACPower hybrid setting to pv config (#16735)
This commit is contained in:
parent
88b9a2b744
commit
5949829117
19 changed files with 651 additions and 419 deletions
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
92
core/site.go
92
core/site.go
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ params:
|
|||
default: 0
|
||||
example: 5000
|
||||
type: float
|
||||
usages: ["battery"]
|
||||
usages: ["pv"]
|
||||
advanced: true
|
||||
- name: vin
|
||||
description:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue