Add soc: min setting to always force-charge to this value (#379)
This commit is contained in:
parent
0a1f7caf55
commit
6a9ca7342d
16 changed files with 503 additions and 274 deletions
|
|
@ -335,7 +335,8 @@ loadpoints:
|
|||
<div class="row">
|
||||
<div class="col-6 col-md-3 mt-3">
|
||||
<div class="mb-2 value">Leistung
|
||||
<i class="text-primary fa fa-temperature-low ml-1" v-if="state.climater=='heating'"></i>
|
||||
<i class="text-warning fas fa-battery-quarter ml-1" v-if="minSoCActive"></i>
|
||||
<i class="text-primary fa fa-temperature-low ml-1" v-else-if="state.climater=='heating'"></i>
|
||||
<i class="text-primary fa fa-temperature-high ml-1" v-else-if="state.climater=='cooling'"></i>
|
||||
<i class="text-primary fa fa-thermometer-half ml-1" v-else-if="state.climater=='on'"></i>
|
||||
</div>
|
||||
|
|
@ -413,6 +414,7 @@ loadpoints:
|
|||
'progress-bar-animated': state.charging,
|
||||
'bg-light': !state.connected,
|
||||
'text-secondary': !state.connected,
|
||||
'bg-warning': state.connected && minSoCActive,
|
||||
}" v-bind:style="{width: socChargeDisplayWidth+'%'}">{{socChargeDisplayValue}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -346,7 +346,12 @@ Vue.component("loadpoint", {
|
|||
Vue.component("loadpoint-details", {
|
||||
template: "#loadpoint-details-template",
|
||||
props: ["state"],
|
||||
mixins: [formatter]
|
||||
mixins: [formatter],
|
||||
computed: {
|
||||
minSoCActive: function () {
|
||||
return this.state.minSoC > 0 && this.state.socCharge < this.state.minSoC;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component("vehicle", {
|
||||
|
|
@ -377,6 +382,9 @@ Vue.component("vehicle", {
|
|||
socCharge += "%";
|
||||
}
|
||||
return socCharge;
|
||||
},
|
||||
minSoCActive: function () {
|
||||
return this.state.minSoC > 0 && this.state.socCharge < this.state.minSoC;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func init() {
|
|||
}
|
||||
|
||||
// setup influx databases
|
||||
func configureDatabase(conf server.InfluxConfig, loadPoints []*core.LoadPoint, in <-chan util.Param) {
|
||||
func configureDatabase(conf server.InfluxConfig, loadPoints []core.LoadPointAPI, in <-chan util.Param) {
|
||||
influx := server.NewInfluxClient(
|
||||
conf.URL,
|
||||
conf.Token,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@ const (
|
|||
minActiveCurrent = 1.0 // minimum current at which a phase is treated as active
|
||||
)
|
||||
|
||||
// SoCConfig defines soc settings, estimation and update behaviour
|
||||
type SoCConfig struct {
|
||||
AlwaysUpdate bool `mapstructure:"alwaysUpdate"`
|
||||
Levels []int `mapstructure:"levels"`
|
||||
Estimate bool `mapstructure:"estimate"`
|
||||
Min int `mapstructure:"min"` // Default minimum SoC, guarded by mutex
|
||||
Target int `mapstructure:"target"` // Default target SoC, guarded by mutex
|
||||
}
|
||||
|
||||
// ThresholdConfig defines enable/disable hysteresis parameters
|
||||
type ThresholdConfig struct {
|
||||
Delay time.Duration
|
||||
|
|
@ -47,8 +56,7 @@ type LoadPoint struct {
|
|||
|
||||
// exposed public configuration
|
||||
sync.Mutex // guard status
|
||||
Mode api.ChargeMode `mapstructure:"mode"` // Charge mode, guarded by mutex
|
||||
TargetSoC int `mapstructure:"targetSoC"` // Target SoC, guarded by mutex
|
||||
Mode api.ChargeMode `mapstructure:"mode"` // Charge mode, guarded by mutex
|
||||
|
||||
Title string `mapstructure:"title"` // UI title
|
||||
Phases int64 `mapstructure:"phases"` // Phases- required for converting power and current
|
||||
|
|
@ -57,11 +65,7 @@ type LoadPoint struct {
|
|||
Meters struct {
|
||||
ChargeMeterRef string `mapstructure:"charge"` // Charge meter reference
|
||||
}
|
||||
SoC struct {
|
||||
AlwaysUpdate bool `mapstructure:"alwaysUpdate"`
|
||||
Levels []int `mapstructure:"levels"`
|
||||
Estimate bool `mapstructure:"estimate"`
|
||||
}
|
||||
SoC SoCConfig
|
||||
OnDisconnect struct {
|
||||
Mode api.ChargeMode `mapstructure:"mode"` // Charge mode to apply when car disconnected
|
||||
TargetSoC int `mapstructure:"targetSoC"` // Target SoC to apply when car disconnected
|
||||
|
|
@ -102,11 +106,14 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
|
|||
lp.OnDisconnect.Mode = api.ChargeModeString(string(lp.OnDisconnect.Mode))
|
||||
|
||||
sort.Ints(lp.SoC.Levels)
|
||||
if lp.TargetSoC == 0 {
|
||||
lp.TargetSoC = 100
|
||||
if lp.SoC.Target == 0 {
|
||||
lp.SoC.Target = lp.OnDisconnect.TargetSoC // use disconnect value as default soc
|
||||
if lp.SoC.Target == 0 {
|
||||
lp.SoC.Target = 100
|
||||
}
|
||||
|
||||
if len(lp.SoC.Levels) > 0 {
|
||||
lp.TargetSoC = lp.SoC.Levels[len(lp.SoC.Levels)-1]
|
||||
lp.SoC.Target = lp.SoC.Levels[len(lp.SoC.Levels)-1]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,50 +169,6 @@ func NewLoadPoint(log *util.Logger) *LoadPoint {
|
|||
return lp
|
||||
}
|
||||
|
||||
// GetMode returns loadpoint charge mode
|
||||
func (lp *LoadPoint) GetMode() api.ChargeMode {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.Mode
|
||||
}
|
||||
|
||||
// SetMode sets loadpoint charge mode
|
||||
func (lp *LoadPoint) SetMode(mode api.ChargeMode) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.INFO.Printf("set charge mode: %s", string(mode))
|
||||
|
||||
// apply immediately
|
||||
if lp.Mode != mode {
|
||||
lp.Mode = mode
|
||||
lp.publish("mode", mode)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
// GetTargetSoC returns loadpoint charge targetSoC
|
||||
func (lp *LoadPoint) GetTargetSoC() int {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.TargetSoC
|
||||
}
|
||||
|
||||
// SetTargetSoC sets loadpoint charge targetSoC
|
||||
func (lp *LoadPoint) SetTargetSoC(targetSoC int) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.INFO.Println("set target soc:", targetSoC)
|
||||
|
||||
// apply immediately
|
||||
if lp.TargetSoC != targetSoC {
|
||||
lp.TargetSoC = targetSoC
|
||||
lp.publish("targetSoC", targetSoC)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
// requestUpdate requests site to update this loadpoint
|
||||
func (lp *LoadPoint) requestUpdate() {
|
||||
select {
|
||||
|
|
@ -309,7 +272,7 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
|
|||
lp.SetMode(lp.OnDisconnect.Mode)
|
||||
}
|
||||
if lp.OnDisconnect.TargetSoC != 0 {
|
||||
lp.SetTargetSoC(lp.OnDisconnect.TargetSoC)
|
||||
_ = lp.SetTargetSoC(lp.OnDisconnect.TargetSoC)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +327,8 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
// publish initial values
|
||||
lp.Lock()
|
||||
lp.publish("mode", lp.Mode)
|
||||
lp.publish("targetSoC", lp.TargetSoC)
|
||||
lp.publish("targetSoC", lp.SoC.Target)
|
||||
lp.publish("minSoC", lp.SoC.Min)
|
||||
lp.Unlock()
|
||||
|
||||
// prepare charger status
|
||||
|
|
@ -376,10 +340,20 @@ func (lp *LoadPoint) connected() bool {
|
|||
return lp.status == api.StatusB || lp.status == api.StatusC
|
||||
}
|
||||
|
||||
// targetSocReached checks if targetSoC configured and reached
|
||||
func (lp *LoadPoint) targetSocReached(socCharge, targetSoC float64) bool {
|
||||
// check for vehicle != nil is not necessary as socCharge would be zero then
|
||||
return targetSoC > 0 && targetSoC < 100 && socCharge >= targetSoC
|
||||
// targetSocReached checks if target is configured and reached.
|
||||
// If vehicle is not configured this will always return false
|
||||
func (lp *LoadPoint) targetSocReached() bool {
|
||||
return lp.vehicle != nil &&
|
||||
lp.SoC.Target > 0 &&
|
||||
lp.socCharge >= float64(lp.SoC.Target)
|
||||
}
|
||||
|
||||
// minSocNotReached checks if minimum is configured and not reached.
|
||||
// If vehicle is not configured this will always return true
|
||||
func (lp *LoadPoint) minSocNotReached() bool {
|
||||
return lp.vehicle != nil &&
|
||||
lp.SoC.Min > 0 &&
|
||||
lp.socCharge < float64(lp.SoC.Min)
|
||||
}
|
||||
|
||||
// climateActive checks if vehicle has active climate request
|
||||
|
|
@ -481,8 +455,13 @@ func (lp *LoadPoint) detectPhases() {
|
|||
}
|
||||
}
|
||||
|
||||
// maxCurrent calculates the maximum target current for PV mode
|
||||
func (lp *LoadPoint) maxCurrent(mode api.ChargeMode, sitePower float64) int64 {
|
||||
// pvDisableTimer puts the pv enable/disable timer into elapsed state
|
||||
func (lp *LoadPoint) pvDisableTimer() {
|
||||
lp.pvTimer = time.Now().Add(-lp.Disable.Delay)
|
||||
}
|
||||
|
||||
// pvMaxCurrent calculates the maximum target current for PV mode
|
||||
func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) int64 {
|
||||
// calculate target charge current from delta power and actual current
|
||||
effectiveCurrent := lp.handler.TargetCurrent()
|
||||
if lp.status != api.StatusC {
|
||||
|
|
@ -624,11 +603,11 @@ func (lp *LoadPoint) publishSoC() {
|
|||
|
||||
chargeEstimate := time.Duration(-1)
|
||||
if lp.charging {
|
||||
chargeEstimate = lp.socEstimator.RemainingChargeDuration(lp.chargePower, lp.TargetSoC)
|
||||
chargeEstimate = lp.socEstimator.RemainingChargeDuration(lp.chargePower, lp.SoC.Target)
|
||||
}
|
||||
lp.publish("chargeEstimate", chargeEstimate)
|
||||
|
||||
chargeRemainingEnergy := 1e3 * lp.socEstimator.RemainingChargeEnergy(lp.TargetSoC)
|
||||
chargeRemainingEnergy := 1e3 * lp.socEstimator.RemainingChargeEnergy(lp.SoC.Target)
|
||||
lp.publish("chargeRemainingEnergy", chargeRemainingEnergy)
|
||||
|
||||
return
|
||||
|
|
@ -684,8 +663,8 @@ func (lp *LoadPoint) Update(sitePower float64) {
|
|||
// https://github.com/andig/evcc/issues/105
|
||||
err = lp.handler.Ramp(0)
|
||||
|
||||
case lp.targetSocReached(lp.socCharge, float64(lp.TargetSoC)):
|
||||
var targetCurrent int64
|
||||
case lp.targetSocReached():
|
||||
var targetCurrent int64 // zero disables
|
||||
if lp.climateActive() {
|
||||
targetCurrent = lp.MinCurrent
|
||||
}
|
||||
|
|
@ -694,11 +673,15 @@ func (lp *LoadPoint) Update(sitePower float64) {
|
|||
case mode == api.ModeOff:
|
||||
err = lp.handler.Ramp(0, true)
|
||||
|
||||
case lp.minSocNotReached():
|
||||
err = lp.handler.Ramp(lp.MaxCurrent, true)
|
||||
lp.pvDisableTimer() // let PV mode disable immediately afterwards
|
||||
|
||||
case mode == api.ModeNow:
|
||||
err = lp.handler.Ramp(lp.MaxCurrent, true)
|
||||
|
||||
case mode == api.ModeMinPV || mode == api.ModePV:
|
||||
targetCurrent := lp.maxCurrent(mode, sitePower)
|
||||
targetCurrent := lp.pvMaxCurrent(mode, sitePower)
|
||||
lp.log.DEBUG.Printf("target charge current: %dA", targetCurrent)
|
||||
|
||||
var required bool // false
|
||||
|
|
|
|||
136
core/loadpoint_api.go
Normal file
136
core/loadpoint_api.go
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/core/wrapper"
|
||||
)
|
||||
|
||||
// LoadPointAPI is the external loadpoint API
|
||||
type LoadPointAPI interface {
|
||||
Name() string
|
||||
HasChargeMeter() bool
|
||||
LoadPointSettingsAPI
|
||||
LoadPointEnergyAPI
|
||||
}
|
||||
|
||||
// LoadPointSettingsAPI is the getter/setter part of the external loadpoint API
|
||||
type LoadPointSettingsAPI interface {
|
||||
GetMode() api.ChargeMode
|
||||
SetMode(api.ChargeMode)
|
||||
GetTargetSoC() int
|
||||
SetTargetSoC(int) error
|
||||
GetMinSoC() int
|
||||
SetMinSoC(int) error
|
||||
}
|
||||
|
||||
// LoadPointEnergyAPI is the external loadpoint API
|
||||
type LoadPointEnergyAPI interface {
|
||||
GetMinCurrent() int64
|
||||
GetMaxCurrent() int64
|
||||
GetMinPower() int64
|
||||
GetMaxPower() int64
|
||||
}
|
||||
|
||||
// GetMode returns loadpoint charge mode
|
||||
func (lp *LoadPoint) GetMode() api.ChargeMode {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.Mode
|
||||
}
|
||||
|
||||
// SetMode sets loadpoint charge mode
|
||||
func (lp *LoadPoint) SetMode(mode api.ChargeMode) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.INFO.Printf("set charge mode: %s", string(mode))
|
||||
|
||||
// apply immediately
|
||||
if lp.Mode != mode {
|
||||
lp.Mode = mode
|
||||
lp.publish("mode", mode)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
// GetTargetSoC returns loadpoint charge target soc
|
||||
func (lp *LoadPoint) GetTargetSoC() int {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.SoC.Target
|
||||
}
|
||||
|
||||
// SetTargetSoC sets loadpoint charge target soc
|
||||
func (lp *LoadPoint) SetTargetSoC(soc int) error {
|
||||
if lp.vehicle == nil {
|
||||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.INFO.Println("set target soc:", soc)
|
||||
|
||||
// apply immediately
|
||||
if lp.SoC.Target != soc {
|
||||
lp.SoC.Target = soc
|
||||
lp.publish("targetSoC", soc)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMinSoC returns loadpoint charge minimum soc
|
||||
func (lp *LoadPoint) GetMinSoC() int {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.SoC.Min
|
||||
}
|
||||
|
||||
// SetMinSoC sets loadpoint charge minimum soc
|
||||
func (lp *LoadPoint) SetMinSoC(soc int) error {
|
||||
if lp.vehicle == nil {
|
||||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.INFO.Println("set min soc:", soc)
|
||||
|
||||
// apply immediately
|
||||
if lp.SoC.Min != soc {
|
||||
lp.SoC.Min = soc
|
||||
lp.publish("minSoC", soc)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasChargeMeter determines if a physical charge meter is attached
|
||||
func (lp *LoadPoint) HasChargeMeter() bool {
|
||||
_, isWrapped := lp.chargeMeter.(*wrapper.ChargeMeter)
|
||||
return lp.chargeMeter != nil && !isWrapped
|
||||
}
|
||||
|
||||
// GetMinCurrent returns the minimal loadpoint current
|
||||
func (lp *LoadPoint) GetMinCurrent() int64 {
|
||||
return lp.MinCurrent
|
||||
}
|
||||
|
||||
// GetMaxCurrent returns the minimal loadpoint current
|
||||
func (lp *LoadPoint) GetMaxCurrent() int64 {
|
||||
return lp.MaxCurrent
|
||||
}
|
||||
|
||||
// GetMinPower returns the minimal loadpoint power for a single phase
|
||||
func (lp *LoadPoint) GetMinPower() int64 {
|
||||
return int64(Voltage) * lp.MinCurrent
|
||||
}
|
||||
|
||||
// GetMaxPower returns the minimal loadpoint power taking active phases into account
|
||||
func (lp *LoadPoint) GetMaxPower() int64 {
|
||||
return int64(Voltage) * lp.Phases * lp.MaxCurrent
|
||||
}
|
||||
|
|
@ -152,9 +152,9 @@ func TestUpdate(t *testing.T) {
|
|||
log: util.NewLogger("foo"),
|
||||
bus: evbus.New(),
|
||||
clock: clck,
|
||||
chargeMeter: &Null{}, //silence nil panics
|
||||
chargeRater: &Null{}, //silence nil panics
|
||||
chargeTimer: &Null{}, //silence nil panics
|
||||
chargeMeter: &Null{}, // silence nil panics
|
||||
chargeRater: &Null{}, // silence nil panics
|
||||
chargeTimer: &Null{}, // silence nil panics
|
||||
HandlerConfig: HandlerConfig{
|
||||
MinCurrent: lpMinCurrent,
|
||||
MaxCurrent: lpMaxCurrent,
|
||||
|
|
@ -330,7 +330,7 @@ func TestPVHysteresisForStatusC(t *testing.T) {
|
|||
handler.EXPECT().TargetCurrent().Return(int64(0))
|
||||
handler.EXPECT().Enabled().Return(tc.enabled)
|
||||
|
||||
current := lp.maxCurrent(api.ModePV, se.site)
|
||||
current := lp.pvMaxCurrent(api.ModePV, se.site)
|
||||
|
||||
if current != se.current {
|
||||
t.Errorf("step %d: wanted %d, got %d", step, se.current, current)
|
||||
|
|
@ -366,7 +366,7 @@ func TestPVHysteresisForStatusOtherThanC(t *testing.T) {
|
|||
|
||||
// maxCurrent will read enabled state in PV mode
|
||||
sitePower := -float64(minA*lp.Phases)*Voltage + 1 // 1W below min power
|
||||
current := lp.maxCurrent(api.ModePV, sitePower)
|
||||
current := lp.pvMaxCurrent(api.ModePV, sitePower)
|
||||
|
||||
if current != 0 {
|
||||
t.Errorf("PV mode could not disable charger as expected. Expected 0, got %d", current)
|
||||
|
|
@ -389,24 +389,27 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) {
|
|||
log: util.NewLogger("foo"),
|
||||
bus: evbus.New(),
|
||||
clock: clock,
|
||||
chargeMeter: &Null{}, //silence nil panics
|
||||
chargeRater: &Null{}, //silence nil panics
|
||||
chargeTimer: &Null{}, //silence nil panics
|
||||
chargeMeter: &Null{}, // silence nil panics
|
||||
chargeRater: &Null{}, // silence nil panics
|
||||
chargeTimer: &Null{}, // silence nil panics
|
||||
HandlerConfig: HandlerConfig{
|
||||
MinCurrent: lpMinCurrent,
|
||||
MaxCurrent: lpMaxCurrent,
|
||||
},
|
||||
handler: handler,
|
||||
vehicle: vehicle, // needed for targetSoC check
|
||||
socEstimator: socEstimator, // instead of vehicle: vehicle,
|
||||
status: api.StatusC,
|
||||
TargetSoC: 90,
|
||||
Mode: api.ModeNow,
|
||||
SoC: SoCConfig{
|
||||
Target: 90,
|
||||
},
|
||||
}
|
||||
|
||||
handler.EXPECT().Prepare().Return()
|
||||
attachListeners(t, lp)
|
||||
|
||||
// charging below target
|
||||
lp.Mode = api.ModeNow
|
||||
handler.EXPECT().TargetCurrent().Return(int64(6))
|
||||
handler.EXPECT().Status().Return(api.StatusC, nil)
|
||||
vehicle.EXPECT().ChargeState().Return(85.0, nil)
|
||||
|
|
@ -454,9 +457,9 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) {
|
|||
log: util.NewLogger("foo"),
|
||||
bus: evbus.New(),
|
||||
clock: clock,
|
||||
chargeMeter: &Null{}, //silence nil panics
|
||||
chargeRater: &Null{}, //silence nil panics
|
||||
chargeTimer: &Null{}, //silence nil panics
|
||||
chargeMeter: &Null{}, // silence nil panics
|
||||
chargeRater: &Null{}, // silence nil panics
|
||||
chargeTimer: &Null{}, // silence nil panics
|
||||
HandlerConfig: HandlerConfig{
|
||||
MinCurrent: lpMinCurrent,
|
||||
MaxCurrent: lpMaxCurrent,
|
||||
|
|
@ -526,9 +529,9 @@ func TestChargedEnergyAtDisconnect(t *testing.T) {
|
|||
log: util.NewLogger("foo"),
|
||||
bus: evbus.New(),
|
||||
clock: clock,
|
||||
chargeMeter: &Null{}, //silence nil panics
|
||||
chargeMeter: &Null{}, // silence nil panics
|
||||
chargeRater: rater,
|
||||
chargeTimer: &Null{}, //silence nil panics
|
||||
chargeTimer: &Null{}, // silence nil panics
|
||||
HandlerConfig: HandlerConfig{
|
||||
MinCurrent: lpMinCurrent,
|
||||
MaxCurrent: lpMaxCurrent,
|
||||
|
|
@ -609,3 +612,81 @@ func TestChargedEnergyAtDisconnect(t *testing.T) {
|
|||
|
||||
ctrl.Finish()
|
||||
}
|
||||
|
||||
func TestTargetSoC(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
vhc := mock.NewMockVehicle(ctrl)
|
||||
|
||||
tc := []struct {
|
||||
vehicle api.Vehicle
|
||||
target int
|
||||
soc float64
|
||||
res bool
|
||||
}{
|
||||
{nil, 0, 0, false}, // never reached without vehicle
|
||||
{nil, 0, 10, false}, // never reached without vehicle
|
||||
{nil, 80, 0, false}, // never reached without vehicle
|
||||
{nil, 80, 80, false}, // never reached without vehicle
|
||||
{nil, 80, 100, false}, // never reached without vehicle
|
||||
{vhc, 0, 0, false}, // target disabled
|
||||
{vhc, 0, 10, false}, // target disabled
|
||||
{vhc, 80, 0, false}, // target not reached
|
||||
{vhc, 80, 80, true}, // target reached
|
||||
{vhc, 80, 100, true}, // target reached
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
t.Logf("%+v", tc)
|
||||
|
||||
lp := &LoadPoint{
|
||||
vehicle: tc.vehicle,
|
||||
SoC: SoCConfig{
|
||||
Target: tc.target,
|
||||
},
|
||||
socCharge: tc.soc,
|
||||
}
|
||||
|
||||
if res := lp.targetSocReached(); tc.res != res {
|
||||
t.Errorf("expected %v, got %v", tc.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinSoC(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
vhc := mock.NewMockVehicle(ctrl)
|
||||
|
||||
tc := []struct {
|
||||
vehicle api.Vehicle
|
||||
min int
|
||||
soc float64
|
||||
res bool
|
||||
}{
|
||||
{nil, 0, 0, false}, // never reached without vehicle
|
||||
{nil, 0, 10, false}, // never reached without vehicle
|
||||
{nil, 80, 0, false}, // never reached without vehicle
|
||||
{nil, 80, 80, false}, // never reached without vehicle
|
||||
{nil, 80, 100, false}, // never reached without vehicle
|
||||
{vhc, 0, 0, false}, // min disabled
|
||||
{vhc, 0, 10, false}, // min disabled
|
||||
{vhc, 80, 0, true}, // min not reached
|
||||
{vhc, 80, 80, false}, // min reached
|
||||
{vhc, 80, 100, false}, // min reached
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
t.Logf("%+v", tc)
|
||||
|
||||
lp := &LoadPoint{
|
||||
vehicle: tc.vehicle,
|
||||
SoC: SoCConfig{
|
||||
Min: tc.min,
|
||||
},
|
||||
socCharge: tc.soc,
|
||||
}
|
||||
|
||||
if res := lp.minSocNotReached(); tc.res != res {
|
||||
t.Errorf("expected %v, got %v", tc.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
core/site.go
40
core/site.go
|
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/core/wrapper"
|
||||
"github.com/andig/evcc/push"
|
||||
"github.com/andig/evcc/util"
|
||||
"github.com/avast/retry-go"
|
||||
|
|
@ -126,43 +125,6 @@ type LoadpointConfiguration struct {
|
|||
TargetSoC int `json:"targetSoC"`
|
||||
}
|
||||
|
||||
// GetMode gets loadpoint charge mode
|
||||
func (site *Site) GetMode() api.ChargeMode {
|
||||
return site.loadpoints[0].GetMode()
|
||||
}
|
||||
|
||||
// GetTargetSoC gets loadpoint charge targetSoC
|
||||
func (site *Site) GetTargetSoC() int {
|
||||
return site.loadpoints[0].GetTargetSoC()
|
||||
}
|
||||
|
||||
// SetMode sets loadpoint charge mode
|
||||
func (site *Site) SetMode(mode api.ChargeMode) {
|
||||
site.log.INFO.Printf("set global charge mode: %s", string(mode))
|
||||
for _, lp := range site.loadpoints {
|
||||
lp.SetMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// SetTargetSoC sets loadpoint charge targetSoC
|
||||
func (site *Site) SetTargetSoC(targetSoC int) {
|
||||
site.log.INFO.Println("set global target soc:", targetSoC)
|
||||
for _, lp := range site.loadpoints {
|
||||
lp.SetTargetSoC(targetSoC)
|
||||
}
|
||||
}
|
||||
|
||||
// HasChargeMeter determines if a physical charge meter is attached
|
||||
func (lp *LoadPoint) HasChargeMeter() bool {
|
||||
_, isWrapped := lp.chargeMeter.(*wrapper.ChargeMeter)
|
||||
return lp.chargeMeter != nil && !isWrapped
|
||||
}
|
||||
|
||||
// LoadPoints returns the array of associated loadpoints
|
||||
func (site *Site) LoadPoints() []*LoadPoint {
|
||||
return site.loadpoints
|
||||
}
|
||||
|
||||
// Configuration returns meter configuration
|
||||
func (site *Site) Configuration() SiteConfiguration {
|
||||
c := SiteConfiguration{
|
||||
|
|
@ -187,7 +149,7 @@ func (site *Site) Configuration() SiteConfiguration {
|
|||
lpc.SoCCapacity = lp.vehicle.Capacity()
|
||||
lpc.SoCTitle = lp.vehicle.Title()
|
||||
lpc.SoCLevels = lp.SoC.Levels
|
||||
lpc.TargetSoC = lp.TargetSoC
|
||||
lpc.TargetSoC = lp.GetTargetSoC()
|
||||
}
|
||||
|
||||
c.LoadPoints = append(c.LoadPoints, lpc)
|
||||
|
|
|
|||
65
core/site_api.go
Normal file
65
core/site_api.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package core
|
||||
|
||||
import "github.com/andig/evcc/api"
|
||||
|
||||
// SiteAPI is the external site API
|
||||
type SiteAPI interface {
|
||||
Healthy() bool
|
||||
Configuration() SiteConfiguration
|
||||
LoadPoints() []LoadPointAPI
|
||||
LoadPointSettingsAPI
|
||||
}
|
||||
|
||||
// LoadPoints returns the array of associated loadpoints
|
||||
func (site *Site) LoadPoints() []LoadPointAPI {
|
||||
res := make([]LoadPointAPI, len(site.loadpoints))
|
||||
for id, lp := range site.loadpoints {
|
||||
res[id] = lp
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetMode gets loadpoint charge mode
|
||||
func (site *Site) GetMode() api.ChargeMode {
|
||||
return site.loadpoints[0].GetMode()
|
||||
}
|
||||
|
||||
// SetMode sets loadpoint charge mode
|
||||
func (site *Site) SetMode(mode api.ChargeMode) {
|
||||
site.log.INFO.Printf("set global charge mode: %s", string(mode))
|
||||
for _, lp := range site.loadpoints {
|
||||
lp.SetMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTargetSoC gets loadpoint charge target soc
|
||||
func (site *Site) GetTargetSoC() int {
|
||||
return site.loadpoints[0].GetTargetSoC()
|
||||
}
|
||||
|
||||
// SetTargetSoC sets loadpoint charge target soc
|
||||
func (site *Site) SetTargetSoC(soc int) error {
|
||||
site.log.INFO.Println("set global target soc:", soc)
|
||||
for _, lp := range site.loadpoints {
|
||||
if err := lp.SetTargetSoC(soc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMinSoC gets loadpoint charge minimum soc
|
||||
func (site *Site) GetMinSoC() int {
|
||||
return site.loadpoints[0].GetMinSoC()
|
||||
}
|
||||
|
||||
// SetMinSoC sets loadpoint charge minimum soc
|
||||
func (site *Site) SetMinSoC(soc int) error {
|
||||
site.log.INFO.Println("set global min soc:", soc)
|
||||
for _, lp := range site.loadpoints {
|
||||
if err := lp.SetMinSoC(soc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -67,8 +67,9 @@ loadpoints:
|
|||
charge: charge # charge meter
|
||||
vehicle: audi
|
||||
mode: pv
|
||||
targetSoC: 100 # charge to 100%
|
||||
soc:
|
||||
min: 0 # immediately charge to 0% regardless of mode unless "off" (disabled)
|
||||
target: 100 # always charge to 100%
|
||||
alwaysUpdate: false # set true to update vehicle soc even when disconnected
|
||||
estimate: false # set true to interpolate between api updates
|
||||
levels: # target soc levels for UI
|
||||
|
|
|
|||
32
go.sum
32
go.sum
|
|
@ -19,7 +19,6 @@ github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154Oa
|
|||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alvaroloes/enumer v1.1.2 h1:5khqHB33TZy1GWCO/lZwcroBFh7u+0j40T83VUbfAMY=
|
||||
github.com/alvaroloes/enumer v1.1.2/go.mod h1:FxrjvuXoDAx9isTJrv4c+T410zFi0DtXIT0m65DJ+Wo=
|
||||
github.com/andig/evcc v0.0.0-20200727161511-d58eb15f2dc9/go.mod h1:8HONEC6cC2s4k0u3QL7GIjrYOZYTOKiiXybw0FIJL0A=
|
||||
github.com/andig/evcc-config v0.0.0-20201007090146-de86a8fc8508 h1:Utyo4NnJg7ERtoTxdbmwZkJJ7V97Uw+PdL3G7FgVSL4=
|
||||
|
|
@ -53,13 +52,11 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepmap/oapi-codegen v1.3.6 h1:Wj44p9A0V0PJ+AUg0BWdyGcsS1LY18U+0rCuPQgK0+o=
|
||||
github.com/deepmap/oapi-codegen v1.3.6/go.mod h1:aBozjEveG+33xPiP55Iw/XbVkhtZHEGLq3nxlX0+hfU=
|
||||
github.com/deepmap/oapi-codegen v1.3.9 h1:8e3ZfNFzwMDJ5kojta1GGS2+RjzWIThwDWgwe9GqQrE=
|
||||
github.com/deepmap/oapi-codegen v1.3.9/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0=
|
||||
|
|
@ -113,7 +110,6 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
|
|
@ -134,11 +130,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
|
|
@ -168,7 +162,6 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
|
|||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
|
|
@ -192,7 +185,6 @@ github.com/influxdata/influxdb-client-go v1.4.0 h1:+KavOkwhLClHFfYcJMHHnTL5CZQhX
|
|||
github.com/influxdata/influxdb-client-go v1.4.0/go.mod h1:S+oZsPivqbcP1S9ur+T+QqXvrYS3NCZeMQtBoH4D1dw=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.1.0 h1:zP2I/Vt+zHpF/8vtdkxI/qr25OgPPec3T6SPy6GesYY=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.1.0/go.mod h1:4m7g+qe8nHTRh+ptGHaR8FGB9yV3pxU93CKDb5bbTfY=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
|
|
@ -221,7 +213,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
|
@ -229,7 +220,6 @@ github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jv
|
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
|
|
@ -271,7 +261,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
|||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
|
|
@ -295,13 +284,11 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1 h1:/I3lTljEEDNYLho3/FUB7iD/oc2cEFgVmbHzV+O0PtU=
|
||||
github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1/go.mod h1:eD5JxqMiuNYyFNmyY9rkJ/slN8y59oEu4Ei7F8OoKWQ=
|
||||
github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf/go.mod h1:+AwQL2mK3Pd3S+TUwg0tYQjid0q1txyNUJuuSmz8Kdk=
|
||||
github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 h1:4lfz0keanz7/gAlvJ7lAe9zmE08HXxifBZJC0AdeGKo=
|
||||
github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/olSdkdL3z68MlyXWzwhvwmwN7KuUFXGb3PoOk=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
||||
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
||||
|
|
@ -319,25 +306,20 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
|
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
|
|
@ -346,7 +328,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
|||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU=
|
||||
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
|
|
@ -364,7 +345,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
|
|
@ -373,9 +353,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.0 h1:DMOzIV76tmoDNE9pX6RSN0aDtCYeCg5VueieJaAo1uw=
|
||||
github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
|
@ -395,14 +373,12 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
|||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20200717102329-c4d965bd1eac h1:LnvR04M0HuzjTbRzMpE5jRHcNu46CvG1FOtMcZAX8C4=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20200717102329-c4d965bd1eac/go.mod h1:sldLyJCKVO9GQkit55U5WPNr9U4KmUn1SCdqFN9Gjb4=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20200831092453-b235d6a65b21 h1:KiwFeqxuXkdnv67iuR2qOiyevfPrO4Ma00Ch+J3Tr5I=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20200831092453-b235d6a65b21/go.mod h1:PQGaIeLLHhwwqQ56gnHJn9xSlwPoI1OeIXyGc/eLP0Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32 h1:5tjfNdR2ki3yYQ842+eX2sQHeiwpKJ0RnHO4IYOc4V8=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
|
@ -440,7 +416,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
|
|||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
|
|
@ -470,7 +445,6 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgN
|
|||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -513,7 +487,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
@ -555,7 +528,6 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
|
@ -570,10 +542,8 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
@ -581,7 +551,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
|
@ -593,7 +562,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ type SEMP struct {
|
|||
// site is the minimal interface for accessing site methods
|
||||
type site interface {
|
||||
Configuration() core.SiteConfiguration
|
||||
LoadPoints() []*core.LoadPoint
|
||||
LoadPoints() []core.LoadPointAPI
|
||||
}
|
||||
|
||||
// New generates SEMP Gateway listening at /semp endpoint
|
||||
|
|
@ -316,7 +316,7 @@ func (s *SEMP) cacheGet(id int, key string) (res util.Param, err error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
func (s *SEMP) deviceInfo(id int, lp *core.LoadPoint) DeviceInfo {
|
||||
func (s *SEMP) deviceInfo(id int, lp core.LoadPointAPI) DeviceInfo {
|
||||
method := MethodEstimation
|
||||
if lp.HasChargeMeter() {
|
||||
method = MethodMeasurement
|
||||
|
|
@ -336,8 +336,8 @@ func (s *SEMP) deviceInfo(id int, lp *core.LoadPoint) DeviceInfo {
|
|||
OptionalEnergy: true,
|
||||
},
|
||||
Characteristics: Characteristics{
|
||||
MinPowerConsumption: 230 * int(lp.MinCurrent),
|
||||
MaxPowerConsumption: 230 * int(lp.Phases*lp.MaxCurrent),
|
||||
MinPowerConsumption: int(lp.GetMinPower()),
|
||||
MaxPowerConsumption: int(lp.GetMaxPower()),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +352,7 @@ func (s *SEMP) allDeviceInfo() (res []DeviceInfo) {
|
|||
return res
|
||||
}
|
||||
|
||||
func (s *SEMP) deviceStatus(id int, lp *core.LoadPoint) DeviceStatus {
|
||||
func (s *SEMP) deviceStatus(id int, lp core.LoadPointAPI) DeviceStatus {
|
||||
var chargePower float64
|
||||
if chargePowerP, err := s.cacheGet(id, "chargePower"); err == nil {
|
||||
chargePower = chargePowerP.Val.(float64)
|
||||
|
|
@ -386,7 +386,7 @@ func (s *SEMP) allDeviceStatus() (res []DeviceStatus) {
|
|||
return res
|
||||
}
|
||||
|
||||
func (s *SEMP) planningRequest(id int, lp *core.LoadPoint) (res PlanningRequest) {
|
||||
func (s *SEMP) planningRequest(id int, lp core.LoadPointAPI) (res PlanningRequest) {
|
||||
mode := api.ModeOff
|
||||
if modeP, err := s.cacheGet(id, "mode"); err == nil {
|
||||
mode = api.ChargeMode(modeP.Val.(string))
|
||||
|
|
|
|||
145
server/assets.go
145
server/assets.go
|
|
@ -3561,7 +3561,7 @@ oJE6K0E084u3ea7ne0X73qsc2P2KOB+ngKecxITsMAgTVJfqMwAA//+21HeD5gEAAA==
|
|||
"/index.html": {
|
||||
name: "index.html",
|
||||
local: "assets/index.html",
|
||||
size: 19874,
|
||||
size: 20017,
|
||||
modtime: 1566640112,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/8R83XLbOJbwvZ/ihKmOkulQsp3fT6H0VbeTnZmdTjbVTidVu7UXIHkkog0CHACU7GRc
|
||||
|
|
@ -3623,85 +3623,86 @@ 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
|
||||
4n6R7f8CAAD//y5pd6WiTQAA
|
||||
fwRtSWq3+iiytrCNQOuV9TeMt6H03FP/9MbfP6UAuiOKd1UY39FGze5m5gekSpd82d/RdI4OVB2N72Ug
|
||||
Z+FJ7bKUn4uz7xJNV9g6mjTYJBmMRjaURJcSQ2aKTo8RmcJGb5Ywe7RbzmajDImmfDm6HY2MLrMDiCRC
|
||||
sBsSyVDmwm7KhxlhiwOICD76ih7a7fnfooVuA35lB73buf6IzJ2WvY1o6RuOcnl1G+E2oJ+yXfJ9tYCv
|
||||
SYnyYPHOMyH1a/9yqcVw9XAjbN0sDAndQralgQbCr1RAa49EiWSPRn5EpT8j1XeglDdK21i5M6U0EN75
|
||||
foYpAIYydb34wmYZdicm7eHijGoElZFUrDcLUmTPOzUwWFhRakY51rnH6hNSqkjMMIXqDou9NLJG0z2E
|
||||
sWBpfWDIjXsD2PLIvVcwtA6mutUqEpv0Xek0G4nFYvTYXpGZ3vMEq9YwstdOvBrtvZPAiTALxGLhC4yE
|
||||
0eSiWV89tCgfBfNzLYq755eL9egABrnrFPoZNDgMg2IhpL57FnPKi9Wo3i0uVvvZtSDDDDuMj+qTZo3e
|
||||
JA0pN7xBGrKld8i3lLe6kPZ8X9CxpYe08+FbeP9xA3THGrmpOnbp4gBF1KViU6QhPeRprYd3pezXwu1e
|
||||
34nk908xt0wuVUdyS9P7V6ym8aher7q25N/ka1yQkunaQezzWWD/+APKNHXvXrvOYxqemUPaTlAPHtB0
|
||||
Zl8/DTuSo+b9yVPbdqlzcebYfmSWJPvp+vqbrza97573bZa7brDaTFAi+eD3E/7Fn4oMmkdYG4DVRcr6
|
||||
tHmG7jz56dPi8lXjFuLJ8fE3r6BxM+DkeXHZUxM0b2YGIIU9we6f2Ued8K6X9lHrTqfSkhaYjqbQWMgp
|
||||
Xz4emF/dAd0FUG2sjabg38glgnNMNKaNWba2UJgIntr3Mrvmbq4IbehW00wX3+yNKrDrTRvuNP7F/ozA
|
||||
FJRI3PX/1+400Cfz+NvRN2aR+vKlO/rR+GPfueRbOJk7T3yDA8r3whCi7KTOgI6l8CkUdpvo0h5Vb+5J
|
||||
b910y048qvY54F7Q174pT1FC5c/h4+qAVmiPYPrTVq1jXPYYkb35cDTwnuNp9/TKIfe8bnaap2+jv5ed
|
||||
7Nkg+a0zMDuq91P7UqB1LU1/9qfBpp3T8z1d7eDxjn/8739vXcrZhcSeuHiQp0RlW2fxbyXH+4+VkW8s
|
||||
Rn3q4Z8uRPX6/rYGaZ8U+E3E2fLRw8891Stz9ah93MleIdpsc42+tbeFht9CDkXnnvjcjtCa5sA2e7H7
|
||||
Fd0Ah9mOWxN9IXsTP4HmIc7p1sW5HX6ykdX1vsOucmtn2fsGdpdc7zOikB8mUst0hQFU19fFHTLzlvIx
|
||||
nGsp8lswlFN+VkqJXF9ff3eXTJHLr2CKXB7I1G/t3HbTP+sE5vbVoyeQnQ7G+QGxbv5VRUHndH2Lvb4H
|
||||
u2Tut9qWsfx+CjI27V4kOMxgjVr9H//1P523foOsH8zbX0hBPlP96y/69vydEfeTKNfXF3ZbdT97XdfY
|
||||
fe6h/0T3QgiNsnEN6qm7alb4961F3Hwz6R9ufpNlfxHb+w60R7GtS4dD+9F9N+VvcGW89YsK8+a31uVu
|
||||
gCiiC+AI1QQYn4k8p3o+f3gg3cTOn9h7gw7SEqy+2OtUUYQ8nTcN2L7aubv4sXqR3YNDg6p7kIji6hWc
|
||||
Hp8eD9PZ7nOcfzQanPoHjYpi/LP6/1E0/kCWVrqGV03cr8ZEE/cDcf8XAAD//2pP41YxTgAA
|
||||
`,
|
||||
},
|
||||
|
||||
"/js/app.js": {
|
||||
name: "app.js",
|
||||
local: "assets/js/app.js",
|
||||
size: 9717,
|
||||
size: 9973,
|
||||
modtime: 1566640112,
|
||||
compressed: `
|
||||
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
|
||||
P36oC/UmAAA=
|
||||
`,
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -24,28 +24,16 @@ type targetSoCJSON struct {
|
|||
TargetSoC int `json:"targetSoC"`
|
||||
}
|
||||
|
||||
type minSoCJSON struct {
|
||||
MinSoC int `json:"minSoC"`
|
||||
}
|
||||
|
||||
type route struct {
|
||||
Methods []string
|
||||
Pattern string
|
||||
HandlerFunc http.HandlerFunc
|
||||
}
|
||||
|
||||
// site is the minimal interface for accessing site methods
|
||||
type site interface {
|
||||
Healthy() bool
|
||||
Configuration() core.SiteConfiguration
|
||||
LoadPoints() []*core.LoadPoint
|
||||
loadpoint
|
||||
}
|
||||
|
||||
// loadpoint is the minimal interface for accessing loadpoint methods
|
||||
type loadpoint interface {
|
||||
GetMode() api.ChargeMode
|
||||
SetMode(api.ChargeMode)
|
||||
GetTargetSoC() int
|
||||
SetTargetSoC(targetSoC int)
|
||||
}
|
||||
|
||||
// routeLogger traces matched routes including their executing time
|
||||
func routeLogger(inner http.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -60,18 +48,19 @@ func routeLogger(inner http.Handler) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func indexHandler(site site, useLocal bool) http.HandlerFunc {
|
||||
func indexHandler(site core.SiteAPI, useLocal bool) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
|
||||
indexTemplate, err := FSString(useLocal, "/index.html")
|
||||
if err != nil {
|
||||
log.FATAL.Fatal("httpd: failed to load embedded template: " + err.Error())
|
||||
log.FATAL.Print("httpd: failed to load embedded template:", err.Error())
|
||||
log.FATAL.Fatal("Make sure templates are included using the `release` build tag or use `make build`")
|
||||
}
|
||||
|
||||
t, err := template.New("evcc").Delims("<<", ">>").Parse(indexTemplate)
|
||||
if err != nil {
|
||||
log.FATAL.Fatal("httpd: failed to create main page template: ", err.Error())
|
||||
log.FATAL.Fatal("httpd: failed to create main page template:", err.Error())
|
||||
}
|
||||
|
||||
if err := t.Execute(w, map[string]interface{}{
|
||||
|
|
@ -80,7 +69,7 @@ func indexHandler(site site, useLocal bool) http.HandlerFunc {
|
|||
"Configured": len(site.LoadPoints()),
|
||||
"Tag": time.Now().Unix(),
|
||||
}); err != nil {
|
||||
log.ERROR.Println("httpd: failed to render main page: ", err.Error())
|
||||
log.ERROR.Println("httpd: failed to render main page:", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -101,7 +90,7 @@ func jsonResponse(w http.ResponseWriter, r *http.Request, content interface{}) {
|
|||
}
|
||||
|
||||
// HealthHandler returns current charge mode
|
||||
func HealthHandler(site site) http.HandlerFunc {
|
||||
func HealthHandler(site core.SiteAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !site.Healthy() {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
@ -114,7 +103,7 @@ func HealthHandler(site site) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// ConfigHandler returns current charge mode
|
||||
func ConfigHandler(site site) http.HandlerFunc {
|
||||
func ConfigHandler(site core.SiteAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := site.Configuration()
|
||||
jsonResponse(w, r, res)
|
||||
|
|
@ -162,7 +151,7 @@ func StateHandler(cache *util.Cache) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// CurrentChargeModeHandler returns current charge mode
|
||||
func CurrentChargeModeHandler(loadpoint loadpoint) http.HandlerFunc {
|
||||
func CurrentChargeModeHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := chargeModeJSON{Mode: loadpoint.GetMode()}
|
||||
jsonResponse(w, r, res)
|
||||
|
|
@ -170,7 +159,7 @@ func CurrentChargeModeHandler(loadpoint loadpoint) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// ChargeModeHandler updates charge mode
|
||||
func ChargeModeHandler(loadpoint loadpoint) http.HandlerFunc {
|
||||
func ChargeModeHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -189,7 +178,7 @@ func ChargeModeHandler(loadpoint loadpoint) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// CurrentTargetSoCHandler returns current target soc
|
||||
func CurrentTargetSoCHandler(loadpoint loadpoint) http.HandlerFunc {
|
||||
func CurrentTargetSoCHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := targetSoCJSON{TargetSoC: loadpoint.GetTargetSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
|
|
@ -197,25 +186,57 @@ func CurrentTargetSoCHandler(loadpoint loadpoint) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// TargetSoCHandler updates target soc
|
||||
func TargetSoCHandler(loadpoint loadpoint) http.HandlerFunc {
|
||||
func TargetSoCHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
socS, ok := vars["soc"]
|
||||
soc, err := strconv.ParseInt(socS, 10, 32)
|
||||
|
||||
if ok && err == nil {
|
||||
err = loadpoint.SetTargetSoC(int(soc))
|
||||
}
|
||||
|
||||
if !ok || err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
loadpoint.SetTargetSoC(int(soc))
|
||||
|
||||
res := targetSoCJSON{TargetSoC: loadpoint.GetTargetSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentMinSoCHandler returns current minimum soc
|
||||
func CurrentMinSoCHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := minSoCJSON{MinSoC: loadpoint.GetMinSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// MinSoCHandler updates minimum soc
|
||||
func MinSoCHandler(loadpoint core.LoadPointSettingsAPI) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
socS, ok := vars["soc"]
|
||||
soc, err := strconv.ParseInt(socS, 10, 32)
|
||||
|
||||
if ok && err == nil {
|
||||
err = loadpoint.SetMinSoC(int(soc))
|
||||
}
|
||||
|
||||
if !ok || err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res := minSoCJSON{MinSoC: loadpoint.GetMinSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// SocketHandler attaches websocket handler to uri
|
||||
func SocketHandler(hub *SocketHub) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -235,7 +256,7 @@ type HTTPd struct {
|
|||
}
|
||||
|
||||
// NewHTTPd creates HTTP server with configured routes for loadpoint
|
||||
func NewHTTPd(url string, site site, hub *SocketHub, cache *util.Cache) *HTTPd {
|
||||
func NewHTTPd(url string, site core.SiteAPI, hub *SocketHub, cache *util.Cache) *HTTPd {
|
||||
var routes = map[string]route{
|
||||
"health": {[]string{"GET"}, "/health", HealthHandler(site)},
|
||||
"config": {[]string{"GET"}, "/config", ConfigHandler(site)},
|
||||
|
|
@ -245,6 +266,8 @@ func NewHTTPd(url string, site site, hub *SocketHub, cache *util.Cache) *HTTPd {
|
|||
"setmode": {[]string{"POST", "OPTIONS"}, "/mode/{mode:[a-z]+}", ChargeModeHandler(site)},
|
||||
"gettargetsoc": {[]string{"GET"}, "/targetsoc", CurrentTargetSoCHandler(site)},
|
||||
"settargetsoc": {[]string{"POST", "OPTIONS"}, "/targetsoc/{soc:[0-9]+}", TargetSoCHandler(site)},
|
||||
"getminsoc": {[]string{"GET"}, "/minsoc", CurrentMinSoCHandler(site)},
|
||||
"setminsoc": {[]string{"POST", "OPTIONS"}, "/minsoc/{soc:[0-9]+}", MinSoCHandler(site)},
|
||||
}
|
||||
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
|
|
@ -284,6 +307,8 @@ func NewHTTPd(url string, site site, hub *SocketHub, cache *util.Cache) *HTTPd {
|
|||
applyRouteHandler(subAPI, routes["setmode"], ChargeModeHandler(lp))
|
||||
applyRouteHandler(subAPI, routes["gettargetsoc"], CurrentTargetSoCHandler(lp))
|
||||
applyRouteHandler(subAPI, routes["settargetsoc"], TargetSoCHandler(lp))
|
||||
applyRouteHandler(subAPI, routes["getminsoc"], CurrentMinSoCHandler(lp))
|
||||
applyRouteHandler(subAPI, routes["setminsoc"], MinSoCHandler(lp))
|
||||
}
|
||||
|
||||
srv := &HTTPd{
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ func (m *Influx) supportedType(p util.Param) bool {
|
|||
}
|
||||
|
||||
// Run Influx publisher
|
||||
func (m *Influx) Run(loadPoints []*core.LoadPoint, in <-chan util.Param) {
|
||||
func (m *Influx) Run(loadPoints []core.LoadPointAPI, in <-chan util.Param) {
|
||||
writer := m.client.WriteAPI(m.org, m.database)
|
||||
|
||||
// log errors
|
||||
|
|
|
|||
|
|
@ -65,25 +65,20 @@ func (m *MQTT) publish(topic string, retained bool, payload interface{}) {
|
|||
m.publishSingleValue(topic, retained, payload)
|
||||
}
|
||||
|
||||
type apiHandler interface {
|
||||
SetMode(api.ChargeMode)
|
||||
SetTargetSoC(int)
|
||||
}
|
||||
|
||||
func (m *MQTT) listenSetters(topic string, apiHandler apiHandler) {
|
||||
func (m *MQTT) listenSetters(topic string, apiHandler core.LoadPointSettingsAPI) {
|
||||
m.Handler.Listen(topic+"/mode/set", func(payload string) {
|
||||
apiHandler.SetMode(api.ChargeMode(payload))
|
||||
})
|
||||
m.Handler.Listen(topic+"/targetsoc/set", func(payload string) {
|
||||
soc, err := strconv.Atoi(payload)
|
||||
if err == nil {
|
||||
apiHandler.SetTargetSoC(soc)
|
||||
_ = apiHandler.SetTargetSoC(soc)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Run starts the MQTT publisher for the MQTT API
|
||||
func (m *MQTT) Run(site *core.Site, in <-chan util.Param) {
|
||||
func (m *MQTT) Run(site core.SiteAPI, in <-chan util.Param) {
|
||||
topic := fmt.Sprintf("%s/site", m.root)
|
||||
m.listenSetters(topic, site)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/andig/evcc/core"
|
||||
)
|
||||
|
||||
// SocketPath is the unix domain socket path
|
||||
|
|
@ -24,7 +26,7 @@ func remoteIfExists(file string) {
|
|||
}
|
||||
|
||||
// HealthListener attaches listener to unix domain socket and runs listener
|
||||
func HealthListener(site site) {
|
||||
func HealthListener(site core.SiteAPI) {
|
||||
remoteIfExists(SocketPath)
|
||||
|
||||
l, err := net.Listen("unix", SocketPath)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue