Skip to content

Commit

Permalink
Move MaxACPower hybrid setting to pv config (#16735)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Oct 19, 2024
1 parent 88b9a2b commit 5949829
Show file tree
Hide file tree
Showing 19 changed files with 555 additions and 323 deletions.
4 changes: 2 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/tools/decorate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
Expand Down
92 changes: 48 additions & 44 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -791,15 +795,15 @@ 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
batteryStart = site.bufferStartSoc > 0 && site.batterySoc > site.bufferStartSoc
}
}

sitePower := site.gridPower + batteryPower - batteryExcessDC + residualPower - site.auxPower - flexiblePower
sitePower := site.gridPower + batteryPower - excessDCPower + residualPower - site.auxPower - flexiblePower

// handle priority
var flexStr string
Expand Down
6 changes: 3 additions & 3 deletions meter/meter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 5949829

Please sign in to comment.