Add MaxACPower hybrid battery setting (#16609)
This commit is contained in:
parent
ccade7c1f0
commit
3a88cb4add
28 changed files with 1472 additions and 171 deletions
|
|
@ -44,6 +44,11 @@ type BatteryCapacity interface {
|
|||
Capacity() float64
|
||||
}
|
||||
|
||||
// BatteryMaxACPower provides max AC power in W
|
||||
type BatteryMaxACPower interface {
|
||||
MaxACPower() float64
|
||||
}
|
||||
|
||||
// ChargeState provides current charging status
|
||||
type ChargeState interface {
|
||||
Status() (ChargeStatus, error)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ var a struct {
|
|||
|
||||
api.Battery
|
||||
api.BatteryCapacity
|
||||
api.BatteryMaxACPower
|
||||
api.BatteryController
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ var dependents = map[string][]string{
|
|||
typ(&a.Meter): {typ(&a.MeterEnergy), typ(&a.PhaseCurrents), typ(&a.PhaseVoltages), typ(&a.PhasePowers)},
|
||||
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.BatteryController)},
|
||||
typ(&a.Battery): {typ(&a.BatteryCapacity), typ(&a.BatteryMaxACPower), typ(&a.BatteryController)},
|
||||
}
|
||||
|
||||
// hasIntersection returns if the slices intersect
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -37,20 +36,6 @@ func currentToPower(current float64, phases int) float64 {
|
|||
return current * float64(phases) * Voltage
|
||||
}
|
||||
|
||||
// sitePower returns the available delta power that the charger might additionally consume
|
||||
// negative value: available power (grid export), positive value: grid import
|
||||
func sitePower(log *util.Logger, maxGrid, grid, battery, residual float64) float64 {
|
||||
// For hybrid inverters, battery can be charged from DC power in excess of
|
||||
// inverter AC rating. This battery charge must not be counted as available for AC consumption.
|
||||
// https://github.com/evcc-io/evcc/issues/2734, https://github.com/evcc-io/evcc/issues/2986
|
||||
if maxGrid > 0 && grid > maxGrid && battery < 0 {
|
||||
log.TRACE.Printf("ignoring excess DC charging due to grid consumption: %.0fW > %.0fW", grid, maxGrid)
|
||||
battery = 0
|
||||
}
|
||||
|
||||
return grid + battery + residual
|
||||
}
|
||||
|
||||
// printPtr returns a string representation of a pointer value
|
||||
func printPtr[T any](format string, v *T) string {
|
||||
if v == nil {
|
||||
|
|
|
|||
|
|
@ -39,13 +39,12 @@ const (
|
|||
AuxMeters = "auxMeters"
|
||||
|
||||
// battery settings
|
||||
BatteryCapacity = "batteryCapacity"
|
||||
BatteryDischargeControl = "batteryDischargeControl"
|
||||
BatteryGridChargeLimit = "batteryGridChargeLimit"
|
||||
BatteryGridChargeActive = "batteryGridChargeActive"
|
||||
BufferSoc = "bufferSoc"
|
||||
BufferStartSoc = "bufferStartSoc"
|
||||
MaxGridSupplyWhileBatteryCharging = "maxGridSupplyWhileBatteryCharging"
|
||||
BatteryCapacity = "batteryCapacity"
|
||||
BatteryDischargeControl = "batteryDischargeControl"
|
||||
BatteryGridChargeLimit = "batteryGridChargeLimit"
|
||||
BatteryGridChargeActive = "batteryGridChargeActive"
|
||||
BufferSoc = "bufferSoc"
|
||||
BufferStartSoc = "bufferStartSoc"
|
||||
|
||||
// battery status
|
||||
Battery = "battery"
|
||||
|
|
|
|||
85
core/site.go
85
core/site.go
|
|
@ -49,11 +49,12 @@ type meterMeasurement struct {
|
|||
|
||||
// batteryMeasurement is used as slice element for publishing structured data
|
||||
type batteryMeasurement struct {
|
||||
Power float64 `json:"power"`
|
||||
Energy float64 `json:"energy,omitempty"`
|
||||
Soc float64 `json:"soc,omitempty"`
|
||||
Capacity float64 `json:"capacity,omitempty"`
|
||||
Controllable bool `json:"controllable"`
|
||||
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"`
|
||||
}
|
||||
|
||||
var _ site.API = (*Site)(nil)
|
||||
|
|
@ -74,9 +75,8 @@ type Site struct {
|
|||
ResidualPower float64 `mapstructure:"residualPower"` // PV meter only: household usage. Grid meter: household safety margin
|
||||
Meters MetersConfig `mapstructure:"meters"` // Meter references
|
||||
// TODO deprecated
|
||||
CircuitRef_ string `mapstructure:"circuit"` // Circuit reference
|
||||
|
||||
MaxGridSupplyWhileBatteryCharging float64 `mapstructure:"maxGridSupplyWhileBatteryCharging"` // ignore battery charging if AC consumption is above this value
|
||||
CircuitRef_ string `mapstructure:"circuit"` // Circuit reference
|
||||
MaxGridSupplyWhileBatteryCharging_ float64 `mapstructure:"maxGridSupplyWhileBatteryCharging"` // ignore battery charging if AC consumption is above this value
|
||||
|
||||
// meters
|
||||
circuit api.Circuit // Circuit
|
||||
|
|
@ -100,12 +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
|
||||
batterySoc float64 // Battery soc
|
||||
batteryMode api.BatteryMode // Battery mode (runtime only, not persisted)
|
||||
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)
|
||||
|
||||
publishCache map[string]any // store last published values to avoid unnecessary republishing
|
||||
}
|
||||
|
|
@ -213,7 +214,7 @@ func (site *Site) Boot(log *util.Logger, loadpoints []*Loadpoint, tariffs *tarif
|
|||
site.log.WARN.Println("battery configured but residualPower is missing or <= 0 (add residualPower: 100 to site), see https://docs.evcc.io/en/docs/reference/configuration/site#residualpower")
|
||||
}
|
||||
|
||||
// Meters used only for monitoring
|
||||
// meters used only for monitoring
|
||||
for _, ref := range site.Meters.ExtMetersRef {
|
||||
dev, err := config.Meters().ByName(ref)
|
||||
if err != nil {
|
||||
|
|
@ -231,6 +232,10 @@ func (site *Site) Boot(log *util.Logger, loadpoints []*Loadpoint, tariffs *tarif
|
|||
site.auxMeters = append(site.auxMeters, dev.Instance())
|
||||
}
|
||||
|
||||
if site.MaxGridSupplyWhileBatteryCharging_ != 0 {
|
||||
site.log.WARN.Println("`MaxGridSupplyWhileBatteryCharging` is deprecated- use `maxACPower` in battery configuration instead")
|
||||
}
|
||||
|
||||
// revert battery mode on shutdown
|
||||
shutdown.Register(func() {
|
||||
if mode := site.GetBatteryMode(); batteryModeModified(mode) {
|
||||
|
|
@ -295,11 +300,6 @@ func (site *Site) restoreSettings() error {
|
|||
}
|
||||
}
|
||||
// TODO migrate from YAML
|
||||
if v, err := settings.Float(keys.MaxGridSupplyWhileBatteryCharging); err == nil {
|
||||
if err := site.SetMaxGridSupplyWhileBatteryCharging(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v, err := settings.Float(keys.PrioritySoc); err == nil {
|
||||
if err := site.SetPrioritySoc(v); err != nil {
|
||||
return err
|
||||
|
|
@ -567,6 +567,7 @@ func (site *Site) updateBatteryMeters() error {
|
|||
var mu sync.Mutex
|
||||
|
||||
site.batteryPower = 0
|
||||
site.batteryExcessDC = 0
|
||||
site.batterySoc = 0
|
||||
|
||||
mm := make([]batteryMeasurement, len(site.batteryMeters))
|
||||
|
|
@ -582,8 +583,21 @@ 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", i+1, power)
|
||||
site.log.DEBUG.Printf("battery %d power: %.0fW"+excessStr, i+1, power)
|
||||
}
|
||||
|
||||
// battery energy (discharge)
|
||||
|
|
@ -629,11 +643,12 @@ func (site *Site) updateBatteryMeters() error {
|
|||
_, controllable := meter.(api.BatteryController)
|
||||
|
||||
mm[i] = batteryMeasurement{
|
||||
Power: power,
|
||||
Energy: energy,
|
||||
Soc: batSoc,
|
||||
Capacity: capacity,
|
||||
Controllable: controllable,
|
||||
Power: power,
|
||||
ExcessDCPower: excessDC,
|
||||
Energy: energy,
|
||||
Soc: batSoc,
|
||||
Capacity: capacity,
|
||||
Controllable: controllable,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -674,10 +689,10 @@ func (site *Site) updateGridMeter() error {
|
|||
|
||||
if res, err := backoff.RetryWithData(site.gridMeter.CurrentPower, bo()); err == nil {
|
||||
site.gridPower = res
|
||||
site.log.DEBUG.Printf("grid meter: %.0fW", res)
|
||||
site.log.DEBUG.Printf("grid power: %.0fW", res)
|
||||
site.publish(keys.GridPower, res)
|
||||
} else {
|
||||
return fmt.Errorf("grid meter: %v", err)
|
||||
return fmt.Errorf("grid power: %v", err)
|
||||
}
|
||||
|
||||
// grid phase currents (signed)
|
||||
|
|
@ -756,6 +771,7 @@ func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, b
|
|||
|
||||
// honour battery priority
|
||||
batteryPower := site.batteryPower
|
||||
batteryExcessDC := site.batteryExcessDC
|
||||
|
||||
// handed to loadpoint
|
||||
var batteryBuffered, batteryStart bool
|
||||
|
|
@ -768,6 +784,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
|
||||
} else {
|
||||
// if battery is above bufferSoc allow using it for charging
|
||||
batteryBuffered = site.bufferSoc > 0 && site.batterySoc > site.bufferSoc
|
||||
|
|
@ -775,18 +792,15 @@ func (site *Site) sitePower(totalChargePower, flexiblePower float64) (float64, b
|
|||
}
|
||||
}
|
||||
|
||||
sitePower := sitePower(site.log, site.GetMaxGridSupplyWhileBatteryCharging(), site.gridPower, batteryPower, site.GetResidualPower())
|
||||
|
||||
// deduct smart loads
|
||||
sitePower -= site.auxPower
|
||||
sitePower := site.gridPower + batteryPower - batteryExcessDC + site.GetResidualPower() - site.auxPower - flexiblePower
|
||||
|
||||
// handle priority
|
||||
var flexStr string
|
||||
if flexiblePower > 0 {
|
||||
site.log.DEBUG.Printf("giving loadpoint priority for additional: %.0fW", flexiblePower)
|
||||
sitePower -= flexiblePower
|
||||
flexStr = fmt.Sprintf(" (including %.0fW prioritized power)", flexiblePower)
|
||||
}
|
||||
|
||||
site.log.DEBUG.Printf("site power: %.0fW", sitePower)
|
||||
site.log.DEBUG.Printf("site power: %.0fW"+flexStr, sitePower)
|
||||
|
||||
return sitePower, batteryBuffered, batteryStart, nil
|
||||
}
|
||||
|
|
@ -975,7 +989,6 @@ func (site *Site) prepare() {
|
|||
site.publish(keys.PrioritySoc, site.prioritySoc)
|
||||
site.publish(keys.BufferSoc, site.bufferSoc)
|
||||
site.publish(keys.BufferStartSoc, site.bufferStartSoc)
|
||||
site.publish(keys.MaxGridSupplyWhileBatteryCharging, site.MaxGridSupplyWhileBatteryCharging)
|
||||
site.publish(keys.BatteryMode, site.batteryMode)
|
||||
site.publish(keys.BatteryDischargeControl, site.batteryDischargeControl)
|
||||
site.publish(keys.ResidualPower, site.GetResidualPower())
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ type API interface {
|
|||
SetBufferSoc(float64) error
|
||||
GetBufferStartSoc() float64
|
||||
SetBufferStartSoc(float64) error
|
||||
GetMaxGridSupplyWhileBatteryCharging() float64
|
||||
SetMaxGridSupplyWhileBatteryCharging(float64) error
|
||||
|
||||
// GetBatteryGridChargeLimit get the grid charge limit
|
||||
GetBatteryGridChargeLimit() *float64
|
||||
|
|
|
|||
|
|
@ -248,31 +248,6 @@ func (site *Site) SetBufferStartSoc(soc float64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (site *Site) GetMaxGridSupplyWhileBatteryCharging() float64 {
|
||||
site.RLock()
|
||||
defer site.RUnlock()
|
||||
return site.MaxGridSupplyWhileBatteryCharging
|
||||
}
|
||||
|
||||
func (site *Site) SetMaxGridSupplyWhileBatteryCharging(power float64) error {
|
||||
site.Lock()
|
||||
defer site.Unlock()
|
||||
|
||||
if len(site.batteryMeters) == 0 {
|
||||
return ErrBatteryNotConfigured
|
||||
}
|
||||
|
||||
site.log.DEBUG.Println("set max grid supply while battery charging:", power)
|
||||
|
||||
if site.MaxGridSupplyWhileBatteryCharging != power {
|
||||
site.MaxGridSupplyWhileBatteryCharging = power
|
||||
settings.SetFloat(keys.MaxGridSupplyWhileBatteryCharging, site.MaxGridSupplyWhileBatteryCharging)
|
||||
site.publish(keys.MaxGridSupplyWhileBatteryCharging, site.MaxGridSupplyWhileBatteryCharging)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetResidualPower returns the ResidualPower
|
||||
func (site *Site) GetResidualPower() float64 {
|
||||
site.RLock()
|
||||
|
|
|
|||
|
|
@ -4,35 +4,9 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSitePower(t *testing.T) {
|
||||
tc := []struct {
|
||||
maxGrid, grid, battery, site float64
|
||||
}{
|
||||
{0, 0, 0, 0}, // silent night
|
||||
{0, 0, 1, 1}, // battery discharging
|
||||
{0, 0, -1, -1}, // battery charging -> negative result cannot occur in reality
|
||||
{0, 1, 0, 1}, // grid import
|
||||
{0, 1, 1, 2}, // grid import + battery discharging
|
||||
{0, -1, 0, -1}, // grid export
|
||||
{0, -1, -1, -2}, // grid export + battery charging
|
||||
{0, 1, -1, 0}, // grid import + battery charging -> should not happen
|
||||
{0.5, 1, -1, 1}, // grid import + DC battery charging
|
||||
}
|
||||
|
||||
log := util.NewLogger("foo")
|
||||
|
||||
for _, tc := range tc {
|
||||
res := sitePower(log, tc.maxGrid, tc.grid, tc.battery, 0)
|
||||
if res != tc.site {
|
||||
t.Errorf("sitePower wanted %.f, got %.f", tc.site, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreenShare(t *testing.T) {
|
||||
tc := []struct {
|
||||
title string
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ site:
|
|||
aux:
|
||||
- aux # list of auxiliary meters for adjusting grid operating point
|
||||
residualPower: 0 # additional household usage margin
|
||||
maxGridSupplyWhileBatteryCharging: 0 # ignore battery charging if AC consumption is above this value
|
||||
|
||||
# loadpoint describes the charger, charge meter and connected vehicle
|
||||
loadpoints:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ type capacity struct {
|
|||
|
||||
// var _ api.BatteryCapacity = (*capacity)(nil)
|
||||
|
||||
// Decorator returns the capacity decorator if capacity is specified or nil otherwise
|
||||
// Decorator returns the capacity decorator
|
||||
func (m *capacity) Decorator() func() float64 {
|
||||
if m.Capacity == 0 {
|
||||
return nil
|
||||
15
meter/battery_power.go
Normal file
15
meter/battery_power.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package meter
|
||||
|
||||
type maxpower struct {
|
||||
MaxACPower float64
|
||||
}
|
||||
|
||||
// MaxACPowerDecorator returns the max AC power decorator
|
||||
func (m *maxpower) Decorator() func() float64 {
|
||||
if m.MaxACPower == 0 {
|
||||
return nil
|
||||
}
|
||||
return func() float64 {
|
||||
return m.MaxACPower
|
||||
}
|
||||
}
|
||||
|
|
@ -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.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.BatteryMaxACPower,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) {
|
||||
|
|
@ -26,6 +26,7 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]interface{}
|
|||
|
||||
// battery
|
||||
capacity `mapstructure:",squash"`
|
||||
maxpower `mapstructure:",squash"`
|
||||
battery `mapstructure:",squash"`
|
||||
Soc *provider.Config // optional
|
||||
LimitSoc *provider.Config // optional
|
||||
|
|
@ -82,7 +83,7 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]interface{}
|
|||
batModeS = cc.battery.ModeController(modeS)
|
||||
}
|
||||
|
||||
res := m.Decorate(energyG, currentsG, voltagesG, powersG, socG, cc.capacity.Decorator(), batModeS)
|
||||
res := m.Decorate(energyG, currentsG, voltagesG, powersG, socG, cc.capacity.Decorator(), cc.maxpower.Decorator(), batModeS)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
@ -107,10 +108,11 @@ func (m *Meter) Decorate(
|
|||
voltages func() (float64, float64, float64, error),
|
||||
powers func() (float64, float64, float64, error),
|
||||
batterySoc func() (float64, error),
|
||||
capacity func() float64,
|
||||
batteryCapacity func() float64,
|
||||
batteryMaxACPower func() float64,
|
||||
setBatteryMode func(api.BatteryMode) error,
|
||||
) api.Meter {
|
||||
return decorateMeter(m, totalEnergy, currents, voltages, powers, batterySoc, capacity, setBatteryMode)
|
||||
return decorateMeter(m, totalEnergy, currents, voltages, powers, batterySoc, batteryCapacity, batteryMaxACPower, setBatteryMode)
|
||||
}
|
||||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func NewMovingAverageFromConfig(ctx context.Context, other map[string]interface{
|
|||
powers = m.Powers
|
||||
}
|
||||
|
||||
return meter.Decorate(totalEnergy, currents, voltages, powers, batterySoc, cc.Meter.capacity.Decorator(), nil), nil
|
||||
return meter.Decorate(totalEnergy, currents, voltages, powers, batterySoc, cc.Meter.capacity.Decorator(), nil, nil), nil
|
||||
}
|
||||
|
||||
type MovingAverage struct {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -138,7 +138,7 @@ func NewOpenWBFromConfig(other map[string]interface{}) (api.Meter, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
res := m.Decorate(nil, currents, nil, nil, soc, capacity, nil)
|
||||
res := m.Decorate(nil, currents, nil, nil, soc, capacity, nil, nil)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ func (s *HTTPd) RegisterSiteHandlers(site site.API, valueChan chan<- util.Param)
|
|||
"batterydischargecontrol": {"POST", "/batterydischargecontrol/{value:[01truefalse]+}", boolHandler(site.SetBatteryDischargeControl, site.GetBatteryDischargeControl)},
|
||||
"batterygridcharge": {"POST", "/batterygridchargelimit/{value:-?[0-9.]+}", floatPtrHandler(pass(site.SetBatteryGridChargeLimit), site.GetBatteryGridChargeLimit)},
|
||||
"batterygridchargedelete": {"DELETE", "/batterygridchargelimit", floatPtrHandler(pass(site.SetBatteryGridChargeLimit), site.GetBatteryGridChargeLimit)},
|
||||
"maxgridsupply": {"POST", "/maxgridsupply/{value:[0-9.]+}", floatHandler(site.SetMaxGridSupplyWhileBatteryCharging, site.GetMaxGridSupplyWhileBatteryCharging)},
|
||||
"prioritysoc": {"POST", "/prioritysoc/{value:[0-9.]+}", floatHandler(site.SetPrioritySoc, site.GetPrioritySoc)},
|
||||
"residualpower": {"POST", "/residualpower/{value:-?[0-9.]+}", floatHandler(site.SetResidualPower, site.GetResidualPower)},
|
||||
"smartcost": {"POST", "/smartcostlimit/{value:-?[0-9.]+}", updateSmartCostLimit(site)},
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ params:
|
|||
- 2
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
|
|
@ -174,4 +175,5 @@ render: |
|
|||
type: writemultiple
|
||||
encoding: uint16
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ params:
|
|||
id: 1
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
|
|
@ -213,4 +214,5 @@ render: |
|
|||
type: writemultiple
|
||||
decode: uint16
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ params:
|
|||
id: 1
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
|
|
@ -175,4 +176,5 @@ render: |
|
|||
type: writemultiple
|
||||
decode: uint16
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ params:
|
|||
advanced: true
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
# battery control
|
||||
- name: watchdog
|
||||
type: duration
|
||||
|
|
@ -110,4 +111,5 @@ render: |
|
|||
type: writemultiple
|
||||
encoding: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ params:
|
|||
advanced: true
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
# battery control
|
||||
- name: minsoc
|
||||
type: number
|
||||
|
|
@ -86,6 +87,7 @@ render: |
|
|||
type: writemultiple
|
||||
encoding: {{ if (eq .endianness "big") }}float32{{ else }}float32s{{ end }}
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
minsoc: {{ .minsoc }} # %
|
||||
maxsoc: {{ .maxsoc }} # %
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ params:
|
|||
de: Der ModbusTCP Server muss aktiviert sein.
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
- name: watchdog
|
||||
type: duration
|
||||
default: 30s
|
||||
|
|
@ -183,4 +184,5 @@ render: |
|
|||
type: writemultiple
|
||||
decode: uint32
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ params:
|
|||
- name: timeout
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
- name: watchdog
|
||||
type: duration
|
||||
default: 60s
|
||||
|
|
@ -206,4 +207,5 @@ render: |
|
|||
type: writemultiple
|
||||
encoding: float32s
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ params:
|
|||
id: 1
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
|
|
@ -129,4 +130,5 @@ render: |
|
|||
type: input
|
||||
decode: uint16
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ params:
|
|||
id: 1
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
|
|
@ -117,4 +118,5 @@ render: |
|
|||
type: input
|
||||
decode: uint16
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ params:
|
|||
choice: ["tcpip", "rs485"]
|
||||
- name: capacity
|
||||
advanced: true
|
||||
- name: maxacpower
|
||||
render: |
|
||||
type: custom
|
||||
# sunspec model 203 (int+sf)/ 213 (float) meter
|
||||
|
|
@ -124,4 +125,5 @@ render: |
|
|||
- 124:ChaState
|
||||
- 802:SoC
|
||||
capacity: {{ .capacity }} # kWh
|
||||
maxacpower: {{ .maxacpower }} # W
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -92,9 +92,21 @@ params:
|
|||
help:
|
||||
de: Akkukapazität in kWh
|
||||
en: Battery capacity in kWh
|
||||
example: "50"
|
||||
example: 50
|
||||
type: float
|
||||
usages: ["vehicle", "battery"]
|
||||
- name: maxacpower
|
||||
description:
|
||||
de: Maximale AC Leistung des Hybrid-Wechselrichters
|
||||
en: Maximum AC power of the hybrid inverter
|
||||
help:
|
||||
de: Maximale AC Leistung des Hybrid-Wechselrichters
|
||||
en: Maximum AC power of the hybrid inverter
|
||||
default: 0
|
||||
example: 5000
|
||||
type: float
|
||||
usages: ["battery"]
|
||||
advanced: true
|
||||
- name: vin
|
||||
description:
|
||||
de: Fahrzeugidentifikationsnummer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue