Improve target charging and refactor loadpoint and site apis (#1470)
This commit is contained in:
parent
7f2eddeab1
commit
3986b75b08
20 changed files with 204 additions and 180 deletions
|
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/charger/easee"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -40,7 +40,7 @@ type Easee struct {
|
|||
status easee.ChargerStatus
|
||||
updated time.Time
|
||||
cache time.Duration
|
||||
lp core.LoadPointAPI
|
||||
lp loadpoint.API
|
||||
//lastSmartCharging bool
|
||||
//lastChargeMode api.ChargeMode
|
||||
log *util.Logger
|
||||
|
|
@ -348,9 +348,9 @@ func (c *Easee) Currents() (float64, float64, float64, error) {
|
|||
err
|
||||
}
|
||||
|
||||
var _ core.LoadpointController = (*Easee)(nil)
|
||||
var _ loadpoint.Controller = (*Easee)(nil)
|
||||
|
||||
// LoadpointControl implements core.LoadpointController
|
||||
func (c *Easee) LoadpointControl(lp core.LoadPointAPI) {
|
||||
// LoadpointControl implements loadpoint.Controller
|
||||
func (c *Easee) LoadpointControl(lp loadpoint.API) {
|
||||
c.lp = lp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/evcc-io/eebus/ship"
|
||||
"github.com/evcc-io/eebus/spine"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/server"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
|
@ -19,7 +19,7 @@ import (
|
|||
type EEBus struct {
|
||||
log *util.Logger
|
||||
cc *communication.ConnectionController
|
||||
lp core.LoadPointAPI
|
||||
lp loadpoint.API
|
||||
forcePVLimits bool
|
||||
|
||||
communicationStandard communication.EVCommunicationStandardEnumType
|
||||
|
|
@ -517,10 +517,10 @@ func (c *EEBus) SoC() (float64, error) {
|
|||
return data.EVData.Measurements.SoC, nil
|
||||
}
|
||||
|
||||
var _ core.LoadpointController = (*EEBus)(nil)
|
||||
var _ loadpoint.Controller = (*EEBus)(nil)
|
||||
|
||||
// LoadpointControl implements core.LoadpointController
|
||||
func (c *EEBus) LoadpointControl(lp core.LoadPointAPI) {
|
||||
// LoadpointControl implements loadpoint.Controller
|
||||
func (c *EEBus) LoadpointControl(lp loadpoint.API) {
|
||||
c.lp = lp
|
||||
|
||||
// set current known min, max current limits
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/proto/pb"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/hems"
|
||||
"github.com/evcc-io/evcc/provider/javascript"
|
||||
"github.com/evcc-io/evcc/provider/mqtt"
|
||||
|
|
@ -94,8 +95,8 @@ func configureSponsorship(token string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// setup influx databases
|
||||
func configureDatabase(conf server.InfluxConfig, loadPoints []core.LoadPointAPI, in <-chan util.Param) {
|
||||
// setup influx database
|
||||
func configureDatabase(conf server.InfluxConfig, loadPoints []loadpoint.API, in <-chan util.Param) {
|
||||
influx := server.NewInfluxClient(
|
||||
conf.URL,
|
||||
conf.Token,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/core/soc"
|
||||
"github.com/evcc-io/evcc/core/wrapper"
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
|
|
@ -120,13 +121,13 @@ type LoadPoint struct {
|
|||
socTimer *soc.Timer
|
||||
|
||||
// cached state
|
||||
status api.ChargeStatus // Charger status
|
||||
remoteDemand RemoteDemand // External status demand
|
||||
chargePower float64 // Charging power
|
||||
chargeCurrents []float64 // Phase currents
|
||||
connectedTime time.Time // Time when vehicle was connected
|
||||
pvTimer time.Time // PV enabled/disable timer
|
||||
phaseTimer time.Time // 1p3p switch timer
|
||||
status api.ChargeStatus // Charger status
|
||||
remoteDemand loadpoint.RemoteDemand // External status demand
|
||||
chargePower float64 // Charging power
|
||||
chargeCurrents []float64 // Phase currents
|
||||
connectedTime time.Time // Time when vehicle was connected
|
||||
pvTimer time.Time // PV enabled/disable timer
|
||||
phaseTimer time.Time // 1p3p switch timer
|
||||
|
||||
vehicleSoc float64 // Vehicle SoC
|
||||
chargedEnergy float64 // Charged energy while connected in Wh
|
||||
|
|
@ -201,7 +202,7 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
|
|||
lp.configureChargerType(lp.charger)
|
||||
|
||||
// allow target charge handler to access loadpoint
|
||||
lp.socTimer = soc.NewTimer(lp.log, lp.adapter(), lp.MaxCurrent)
|
||||
lp.socTimer = soc.NewTimer(lp.log, &adapter{LoadPoint: lp})
|
||||
if lp.Enable.Threshold > lp.Disable.Threshold {
|
||||
log.WARN.Printf("PV mode enable threshold (%.0fW) is larger than disable threshold (%.0fW)", lp.Enable.Threshold, lp.Disable.Threshold)
|
||||
} else if lp.Enable.Threshold > 0 {
|
||||
|
|
@ -454,7 +455,7 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
}
|
||||
|
||||
// allow charger to access loadpoint
|
||||
if ctrl, ok := lp.charger.(LoadpointController); ok {
|
||||
if ctrl, ok := lp.charger.(loadpoint.Controller); ok {
|
||||
ctrl.LoadpointControl(lp)
|
||||
}
|
||||
}
|
||||
|
|
@ -602,7 +603,7 @@ func (lp *LoadPoint) climateActive() bool {
|
|||
}
|
||||
|
||||
// remoteControlled returns true if remote control status is active
|
||||
func (lp *LoadPoint) remoteControlled(demand RemoteDemand) bool {
|
||||
func (lp *LoadPoint) remoteControlled(demand loadpoint.RemoteDemand) bool {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
|
|
@ -1245,7 +1246,7 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool) {
|
|||
var err error
|
||||
|
||||
// track if remote disabled is actually active
|
||||
remoteDisabled := RemoteEnable
|
||||
remoteDisabled := loadpoint.RemoteEnable
|
||||
|
||||
// execute loading strategy
|
||||
switch {
|
||||
|
|
@ -1265,8 +1266,8 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool) {
|
|||
lp.socTimer.Reset() // once SoC is reached, the target charge request is removed
|
||||
|
||||
// OCPP has priority over target charging
|
||||
case lp.remoteControlled(RemoteHardDisable):
|
||||
remoteDisabled = RemoteHardDisable
|
||||
case lp.remoteControlled(loadpoint.RemoteHardDisable):
|
||||
remoteDisabled = loadpoint.RemoteHardDisable
|
||||
fallthrough
|
||||
|
||||
case mode == api.ModeOff:
|
||||
|
|
@ -1286,9 +1287,9 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool) {
|
|||
}
|
||||
|
||||
// target charging
|
||||
case lp.socTimer.StartRequired():
|
||||
case lp.socTimer.DemandActive():
|
||||
targetCurrent := lp.socTimer.Handle()
|
||||
err = lp.setLimit(targetCurrent, false)
|
||||
err = lp.setLimit(targetCurrent, true)
|
||||
|
||||
case mode == api.ModeMinPV || mode == api.ModePV:
|
||||
targetCurrent := lp.pvMaxCurrent(mode, sitePower)
|
||||
|
|
@ -1308,8 +1309,8 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool) {
|
|||
}
|
||||
|
||||
// Sunny Home Manager
|
||||
if lp.remoteControlled(RemoteSoftDisable) {
|
||||
remoteDisabled = RemoteSoftDisable
|
||||
if lp.remoteControlled(loadpoint.RemoteSoftDisable) {
|
||||
remoteDisabled = loadpoint.RemoteSoftDisable
|
||||
targetCurrent = 0
|
||||
required = true
|
||||
}
|
||||
|
|
@ -1318,7 +1319,7 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool) {
|
|||
}
|
||||
|
||||
// effective disabled status
|
||||
if remoteDisabled != RemoteEnable {
|
||||
if remoteDisabled != loadpoint.RemoteEnable {
|
||||
lp.publish("remoteDisabled", remoteDisabled)
|
||||
}
|
||||
|
||||
|
|
|
|||
43
core/loadpoint/api.go
Normal file
43
core/loadpoint/api.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package loadpoint
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
// Controller gives access to loadpoint
|
||||
type Controller interface {
|
||||
LoadpointControl(API)
|
||||
}
|
||||
|
||||
// API is the external loadpoint API
|
||||
type API interface {
|
||||
Name() string
|
||||
HasChargeMeter() bool
|
||||
|
||||
// status
|
||||
GetStatus() api.ChargeStatus
|
||||
|
||||
// settings
|
||||
GetMode() api.ChargeMode
|
||||
SetMode(api.ChargeMode)
|
||||
GetTargetSoC() int
|
||||
SetTargetSoC(int) error
|
||||
GetMinSoC() int
|
||||
SetMinSoC(int) error
|
||||
GetPhases() int
|
||||
SetPhases(int) error
|
||||
|
||||
SetTargetCharge(time.Time, int)
|
||||
RemoteControl(string, RemoteDemand)
|
||||
|
||||
// energy
|
||||
GetChargePower() float64
|
||||
GetMinCurrent() float64
|
||||
SetMinCurrent(float64)
|
||||
GetMaxCurrent() float64
|
||||
SetMaxCurrent(float64)
|
||||
GetMinPower() float64
|
||||
GetMaxPower() float64
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package core
|
||||
package loadpoint
|
||||
|
||||
import "strings"
|
||||
|
||||
|
|
@ -1,27 +1,19 @@
|
|||
package core
|
||||
|
||||
import "github.com/evcc-io/evcc/core/soc"
|
||||
import (
|
||||
"github.com/evcc-io/evcc/core/soc"
|
||||
)
|
||||
|
||||
var _ soc.Adapter = (*adapter)(nil)
|
||||
|
||||
type adapter struct {
|
||||
lp *LoadPoint
|
||||
}
|
||||
|
||||
func (lp *LoadPoint) adapter() soc.Adapter {
|
||||
return &adapter{lp: lp}
|
||||
*LoadPoint
|
||||
}
|
||||
|
||||
func (a *adapter) Publish(key string, val interface{}) {
|
||||
a.lp.publish(key, val)
|
||||
a.LoadPoint.publish(key, val)
|
||||
}
|
||||
|
||||
func (a *adapter) SocEstimator() *soc.Estimator {
|
||||
return a.lp.socEstimator
|
||||
}
|
||||
|
||||
func (a *adapter) ActivePhases() int {
|
||||
return a.lp.activePhases
|
||||
}
|
||||
|
||||
func (a *adapter) Voltage() float64 {
|
||||
return Voltage
|
||||
return a.LoadPoint.socEstimator
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,43 +4,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/core/wrapper"
|
||||
)
|
||||
|
||||
// LoadpointController gives access to loadpoint
|
||||
type LoadpointController interface {
|
||||
LoadpointControl(LoadPointAPI)
|
||||
}
|
||||
|
||||
// LoadPointAPI is the external loadpoint API
|
||||
type LoadPointAPI interface {
|
||||
Name() string
|
||||
HasChargeMeter() bool
|
||||
|
||||
// status
|
||||
GetStatus() api.ChargeStatus
|
||||
|
||||
// settings
|
||||
GetMode() api.ChargeMode
|
||||
SetMode(api.ChargeMode)
|
||||
GetTargetSoC() int
|
||||
SetTargetSoC(int) error
|
||||
GetMinSoC() int
|
||||
SetMinSoC(int) error
|
||||
GetPhases() int
|
||||
SetPhases(int) error
|
||||
SetTargetCharge(time.Time, int)
|
||||
RemoteControl(string, RemoteDemand)
|
||||
|
||||
// energy
|
||||
GetChargePower() float64
|
||||
GetMinCurrent() float64
|
||||
SetMinCurrent(float64)
|
||||
GetMaxCurrent() float64
|
||||
SetMaxCurrent(float64)
|
||||
GetMinPower() float64
|
||||
GetMaxPower() float64
|
||||
}
|
||||
var _ loadpoint.API = (*LoadPoint)(nil)
|
||||
|
||||
// GetStatus returns the charging status
|
||||
func (lp *LoadPoint) GetStatus() api.ChargeStatus {
|
||||
|
|
@ -163,7 +131,7 @@ func (lp *LoadPoint) SetTargetCharge(finishAt time.Time, targetSoC int) {
|
|||
}
|
||||
|
||||
// RemoteControl sets remote status demand
|
||||
func (lp *LoadPoint) RemoteControl(source string, demand RemoteDemand) {
|
||||
func (lp *LoadPoint) RemoteControl(source string, demand loadpoint.RemoteDemand) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/avast/retry-go/v3"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/push"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
|
@ -105,8 +106,8 @@ func NewSite() *Site {
|
|||
}
|
||||
|
||||
// LoadPoints returns the array of associated loadpoints
|
||||
func (site *Site) LoadPoints() []LoadPointAPI {
|
||||
res := make([]LoadPointAPI, len(site.loadpoints))
|
||||
func (site *Site) LoadPoints() []loadpoint.API {
|
||||
res := make([]loadpoint.API, len(site.loadpoints))
|
||||
for id, lp := range site.loadpoints {
|
||||
res[id] = lp
|
||||
}
|
||||
|
|
|
|||
10
core/site/api.go
Normal file
10
core/site/api.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package site
|
||||
|
||||
import "github.com/evcc-io/evcc/core/loadpoint"
|
||||
|
||||
// API is the external site API
|
||||
type API interface {
|
||||
Healthy() bool
|
||||
LoadPoints() []loadpoint.API
|
||||
SetPrioritySoC(float64) error
|
||||
}
|
||||
|
|
@ -4,14 +4,10 @@ import (
|
|||
"errors"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
)
|
||||
|
||||
// SiteAPI is the external site API
|
||||
type SiteAPI interface {
|
||||
Healthy() bool
|
||||
LoadPoints() []LoadPointAPI
|
||||
SetPrioritySoC(float64) error
|
||||
}
|
||||
var _ site.API = (*Site)(nil)
|
||||
|
||||
// GetPrioritySoC returns the PrioritySoC
|
||||
func (site *Site) GetPrioritySoC() float64 {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestSiteApi(t *testing.T) {
|
||||
var _ SiteAPI = NewSite()
|
||||
}
|
||||
|
||||
func TestSitePower(t *testing.T) {
|
||||
tc := []struct {
|
||||
grid, battery, site float64
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
package soc
|
||||
|
||||
import "github.com/evcc-io/evcc/core/loadpoint"
|
||||
|
||||
// Adapter provides the required methods for interacting with the loadpoint
|
||||
type Adapter interface {
|
||||
loadpoint.API
|
||||
Publish(key string, val interface{})
|
||||
SocEstimator() *Estimator
|
||||
ActivePhases() int
|
||||
Voltage() float64
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
|
|
@ -14,21 +15,19 @@ const (
|
|||
// Timer is the target charging handler
|
||||
type Timer struct {
|
||||
Adapter
|
||||
log *util.Logger
|
||||
maxCurrent float64
|
||||
current float64
|
||||
SoC int
|
||||
Time time.Time
|
||||
finishAt time.Time
|
||||
chargeRequired bool
|
||||
log *util.Logger
|
||||
current float64
|
||||
SoC int
|
||||
Time time.Time
|
||||
finishAt time.Time
|
||||
active bool
|
||||
}
|
||||
|
||||
// NewTimer creates a Timer
|
||||
func NewTimer(log *util.Logger, adapter Adapter, maxCurrent float64) *Timer {
|
||||
func NewTimer(log *util.Logger, api Adapter) *Timer {
|
||||
lp := &Timer{
|
||||
log: log,
|
||||
Adapter: adapter,
|
||||
maxCurrent: maxCurrent,
|
||||
log: log,
|
||||
Adapter: api,
|
||||
}
|
||||
|
||||
return lp
|
||||
|
|
@ -40,62 +39,74 @@ func (lp *Timer) Reset() {
|
|||
return
|
||||
}
|
||||
|
||||
lp.current = float64(lp.maxCurrent)
|
||||
lp.current = float64(lp.GetMaxCurrent())
|
||||
lp.Time = time.Time{}
|
||||
lp.SoC = 0
|
||||
}
|
||||
|
||||
// StartRequired calculates remaining charge duration and returns true if charge start is required to achieve target soc in time
|
||||
func (lp *Timer) StartRequired() bool {
|
||||
// DemandActive calculates remaining charge duration and returns true if charge start is required to achieve target soc in time
|
||||
func (lp *Timer) DemandActive() bool {
|
||||
if lp == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
se := lp.SocEstimator()
|
||||
if !lp.active() || se == nil {
|
||||
if se == nil {
|
||||
lp.log.WARN.Printf("target charging: not possible")
|
||||
return false
|
||||
}
|
||||
|
||||
power := float64(lp.ActivePhases()) * lp.maxCurrent * lp.Voltage()
|
||||
defer func() {
|
||||
lp.Publish("timerSet", lp.Time.After(time.Now()))
|
||||
lp.Publish("timerActive", lp.active)
|
||||
lp.Publish("timerProjectedEnd", lp.finishAt)
|
||||
}()
|
||||
|
||||
// power
|
||||
power := lp.GetMaxPower()
|
||||
if lp.active {
|
||||
power *= lp.current / lp.GetMaxCurrent()
|
||||
}
|
||||
|
||||
// time
|
||||
remainingDuration := se.RemainingChargeDuration(power, lp.SoC)
|
||||
lp.finishAt = time.Now().Add(remainingDuration).Round(time.Minute)
|
||||
lp.log.DEBUG.Printf("target charging active for %v: projected %v (%v remaining)", lp.Time, lp.finishAt, remainingDuration.Round(time.Minute))
|
||||
|
||||
lp.chargeRequired = lp.finishAt.After(lp.Time)
|
||||
lp.Publish("timerActive", lp.chargeRequired)
|
||||
// timer charging is already active- only deactivate once charging has stopped
|
||||
if lp.active {
|
||||
if time.Now().After(lp.Time) && lp.GetStatus() != api.StatusC {
|
||||
lp.log.TRACE.Printf("target charging: deactivating")
|
||||
lp.active = false
|
||||
}
|
||||
|
||||
return lp.chargeRequired
|
||||
}
|
||||
|
||||
// active returns true if there is an active target charging request
|
||||
func (lp *Timer) active() bool {
|
||||
inactive := lp.Time.IsZero() || lp.Time.Before(time.Now())
|
||||
lp.Publish("timerSet", !inactive)
|
||||
|
||||
// reset active
|
||||
if inactive && lp.chargeRequired {
|
||||
lp.chargeRequired = false
|
||||
lp.Publish("timerActive", lp.chargeRequired)
|
||||
return lp.active
|
||||
}
|
||||
|
||||
return !inactive
|
||||
// check if charging need be activated
|
||||
if lp.active = lp.finishAt.After(lp.Time); lp.active {
|
||||
lp.current = lp.GetMaxCurrent()
|
||||
lp.log.DEBUG.Printf("target charging active for %v: projected %v (%v remaining)", lp.Time, lp.finishAt, remainingDuration.Round(time.Minute))
|
||||
}
|
||||
|
||||
return lp.active
|
||||
}
|
||||
|
||||
// Handle adjusts current up/down to achieve desired target time taking.
|
||||
func (lp *Timer) Handle() float64 {
|
||||
action := "steady"
|
||||
|
||||
switch {
|
||||
case lp.finishAt.Before(lp.Time.Add(-deviation)):
|
||||
lp.current--
|
||||
lp.log.DEBUG.Printf("target charging: slowdown")
|
||||
action = "slowdown"
|
||||
|
||||
case lp.finishAt.After(lp.Time):
|
||||
lp.current++
|
||||
lp.log.DEBUG.Printf("target charging: speedup")
|
||||
action = "speedup"
|
||||
}
|
||||
|
||||
lp.current = math.Max(math.Min(lp.current, float64(lp.maxCurrent)), 0)
|
||||
lp.current = math.Max(math.Min(lp.current, lp.GetMaxCurrent()), lp.GetMinCurrent())
|
||||
lp.log.DEBUG.Printf("target charging: %s (%.3gA)", action, lp.current)
|
||||
|
||||
return lp.current
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
"github.com/evcc-io/evcc/hems/ocpp/profile"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
|
||||
ocppcore "github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
|
||||
"github.com/lorenzodonini/ocpp-go/ws"
|
||||
|
|
@ -21,14 +21,14 @@ import (
|
|||
type OCPP struct {
|
||||
log *util.Logger
|
||||
cache *util.Cache
|
||||
site core.SiteAPI
|
||||
site site.API
|
||||
cp ocpp16.ChargePoint
|
||||
}
|
||||
|
||||
const retryTimeout = 5 * time.Second
|
||||
|
||||
// New generates OCPP chargepoint client
|
||||
func New(conf map[string]interface{}, site core.SiteAPI, cache *util.Cache) (*OCPP, error) {
|
||||
func New(conf map[string]interface{}, site site.API, cache *util.Cache) (*OCPP, error) {
|
||||
cc := struct {
|
||||
URI string
|
||||
StationID string
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import (
|
|||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
"github.com/evcc-io/evcc/server"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/google/uuid"
|
||||
|
|
@ -49,11 +50,11 @@ type SEMP struct {
|
|||
uid string
|
||||
hostURI string
|
||||
port int
|
||||
site core.SiteAPI
|
||||
site site.API
|
||||
}
|
||||
|
||||
// New generates SEMP Gateway listening at /semp endpoint
|
||||
func New(conf map[string]interface{}, site core.SiteAPI, cache *util.Cache, httpd *server.HTTPd) (*SEMP, error) {
|
||||
func New(conf map[string]interface{}, site site.API, cache *util.Cache, httpd *server.HTTPd) (*SEMP, error) {
|
||||
cc := struct {
|
||||
VendorID string
|
||||
DeviceID string
|
||||
|
|
@ -363,7 +364,7 @@ func (s *SEMP) deviceID(id int) string {
|
|||
return fmt.Sprintf(sempDeviceId, s.vid, ^uint64(0xffff<<48)&(binary.BigEndian.Uint64(did)+uint64(id)))
|
||||
}
|
||||
|
||||
func (s *SEMP) deviceInfo(id int, lp core.LoadPointAPI) DeviceInfo {
|
||||
func (s *SEMP) deviceInfo(id int, lp loadpoint.API) DeviceInfo {
|
||||
method := MethodEstimation
|
||||
if lp.HasChargeMeter() {
|
||||
method = MethodMeasurement
|
||||
|
|
@ -399,7 +400,7 @@ func (s *SEMP) allDeviceInfo() (res []DeviceInfo) {
|
|||
return res
|
||||
}
|
||||
|
||||
func (s *SEMP) deviceStatus(id int, lp core.LoadPointAPI) DeviceStatus {
|
||||
func (s *SEMP) deviceStatus(id int, lp loadpoint.API) DeviceStatus {
|
||||
chargePower := lp.GetChargePower()
|
||||
|
||||
mode := lp.GetMode()
|
||||
|
|
@ -438,7 +439,7 @@ func (s *SEMP) allDeviceStatus() (res []DeviceStatus) {
|
|||
|
||||
// TODO remove GetChecked function
|
||||
|
||||
func (s *SEMP) planningRequest(id int, lp core.LoadPointAPI) (res PlanningRequest) {
|
||||
func (s *SEMP) planningRequest(id int, lp loadpoint.API) (res PlanningRequest) {
|
||||
mode := lp.GetMode()
|
||||
charging := lp.GetStatus() == api.StatusC
|
||||
connected := charging || lp.GetStatus() == api.StatusB
|
||||
|
|
@ -531,9 +532,9 @@ func (s *SEMP) deviceControlHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
demand := core.RemoteSoftDisable
|
||||
demand := loadpoint.RemoteSoftDisable
|
||||
if dev.On {
|
||||
demand = core.RemoteEnable
|
||||
demand = loadpoint.RemoteEnable
|
||||
}
|
||||
|
||||
lp.RemoteControl(sempController, demand)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/test"
|
||||
"github.com/gorilla/handlers"
|
||||
|
|
@ -61,7 +62,7 @@ func routeLogger(inner http.Handler) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func indexHandler(site core.SiteAPI) http.HandlerFunc {
|
||||
func indexHandler(site site.API) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ func jsonResponse(w http.ResponseWriter, r *http.Request, content interface{}) {
|
|||
}
|
||||
|
||||
// HealthHandler returns current charge mode
|
||||
func HealthHandler(site core.SiteAPI) http.HandlerFunc {
|
||||
func HealthHandler(site site.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !site.Healthy() {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
@ -155,15 +156,15 @@ func StateHandler(cache *util.Cache) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// CurrentChargeModeHandler returns current charge mode
|
||||
func CurrentChargeModeHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func CurrentChargeModeHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := chargeModeJSON{Mode: loadpoint.GetMode()}
|
||||
res := chargeModeJSON{Mode: lp.GetMode()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// ChargeModeHandler updates charge mode
|
||||
func ChargeModeHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func ChargeModeHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -176,23 +177,23 @@ func ChargeModeHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
loadpoint.SetMode(mode)
|
||||
lp.SetMode(mode)
|
||||
|
||||
res := chargeModeJSON{Mode: loadpoint.GetMode()}
|
||||
res := chargeModeJSON{Mode: lp.GetMode()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentTargetSoCHandler returns current target soc
|
||||
func CurrentTargetSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func CurrentTargetSoCHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := targetSoCJSON{TargetSoC: loadpoint.GetTargetSoC()}
|
||||
res := targetSoCJSON{TargetSoC: lp.GetTargetSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// TargetSoCHandler updates target soc
|
||||
func TargetSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func TargetSoCHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -200,7 +201,7 @@ func TargetSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
soc, err := strconv.ParseInt(socS, 10, 32)
|
||||
|
||||
if err == nil {
|
||||
err = loadpoint.SetTargetSoC(int(soc))
|
||||
err = lp.SetTargetSoC(int(soc))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -209,21 +210,21 @@ func TargetSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
res := targetSoCJSON{TargetSoC: loadpoint.GetTargetSoC()}
|
||||
res := targetSoCJSON{TargetSoC: lp.GetTargetSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentMinSoCHandler returns current minimum soc
|
||||
func CurrentMinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func CurrentMinSoCHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := minSoCJSON{MinSoC: loadpoint.GetMinSoC()}
|
||||
res := minSoCJSON{MinSoC: lp.GetMinSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// MinSoCHandler updates minimum soc
|
||||
func MinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func MinSoCHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -231,7 +232,7 @@ func MinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
soc, err := strconv.ParseInt(socS, 10, 32)
|
||||
|
||||
if err == nil {
|
||||
err = loadpoint.SetMinSoC(int(soc))
|
||||
err = lp.SetMinSoC(int(soc))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -240,21 +241,21 @@ func MinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
res := minSoCJSON{MinSoC: loadpoint.GetMinSoC()}
|
||||
res := minSoCJSON{MinSoC: lp.GetMinSoC()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentPhasesHandler returns current minimum soc
|
||||
func CurrentPhasesHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func CurrentPhasesHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
res := phasesJSON{Phases: loadpoint.GetPhases()}
|
||||
res := phasesJSON{Phases: lp.GetPhases()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// PhasesHandler updates minimum soc
|
||||
func PhasesHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func PhasesHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -262,7 +263,7 @@ func PhasesHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
phases, err := strconv.ParseInt(phasesS, 10, 32)
|
||||
|
||||
if err == nil {
|
||||
err = loadpoint.SetPhases(int(phases))
|
||||
err = lp.SetPhases(int(phases))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -271,13 +272,13 @@ func PhasesHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
res := phasesJSON{Phases: loadpoint.GetPhases()}
|
||||
res := phasesJSON{Phases: lp.GetPhases()}
|
||||
jsonResponse(w, r, res)
|
||||
}
|
||||
}
|
||||
|
||||
// RemoteDemandHandler updates minimum soc
|
||||
func RemoteDemandHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func RemoteDemandHandler(lp loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -288,7 +289,7 @@ func RemoteDemandHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
source, ok = vars["source"]
|
||||
}
|
||||
|
||||
demand, err := core.RemoteDemandString(demandS)
|
||||
demand, err := loadpoint.RemoteDemandString(demandS)
|
||||
|
||||
if !ok || err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
|
|
@ -296,11 +297,11 @@ func RemoteDemandHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
loadpoint.RemoteControl(source, demand)
|
||||
lp.RemoteControl(source, demand)
|
||||
|
||||
res := struct {
|
||||
Demand core.RemoteDemand `json:"demand"`
|
||||
Source string `json:"source"`
|
||||
Demand loadpoint.RemoteDemand `json:"demand"`
|
||||
Source string `json:"source"`
|
||||
}{
|
||||
Source: source,
|
||||
Demand: demand,
|
||||
|
|
@ -321,7 +322,7 @@ func timezone() *time.Location {
|
|||
}
|
||||
|
||||
// TargetChargeHandler updates target soc
|
||||
func TargetChargeHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
||||
func TargetChargeHandler(loadpoint loadpoint.API) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
|
|
@ -369,7 +370,7 @@ type HTTPd struct {
|
|||
}
|
||||
|
||||
// NewHTTPd creates HTTP server with configured routes for loadpoint
|
||||
func NewHTTPd(url string, site core.SiteAPI, hub *SocketHub, cache *util.Cache) *HTTPd {
|
||||
func NewHTTPd(url string, site site.API, hub *SocketHub, cache *util.Cache) *HTTPd {
|
||||
routes := map[string]route{
|
||||
"health": {[]string{"GET"}, "/health", HealthHandler(site)},
|
||||
"state": {[]string{"GET"}, "/state", StateHandler(cache)},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||
influxlog "github.com/influxdata/influxdb-client-go/v2/log"
|
||||
|
|
@ -73,7 +73,7 @@ func (m *Influx) supportedType(p util.Param) bool {
|
|||
}
|
||||
|
||||
// Run Influx publisher
|
||||
func (m *Influx) Run(loadPoints []core.LoadPointAPI, in <-chan util.Param) {
|
||||
func (m *Influx) Run(loadPoints []loadpoint.API, in <-chan util.Param) {
|
||||
writer := m.client.WriteAPI(m.org, m.database)
|
||||
|
||||
// log errors
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
"github.com/evcc-io/evcc/provider/mqtt"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
|
@ -64,7 +65,7 @@ func (m *MQTT) publish(topic string, retained bool, payload interface{}) {
|
|||
m.publishSingleValue(topic, retained, payload)
|
||||
}
|
||||
|
||||
func (m *MQTT) listenSetters(topic string, apiHandler core.LoadPointAPI) {
|
||||
func (m *MQTT) listenSetters(topic string, apiHandler loadpoint.API) {
|
||||
m.Handler.Listen(topic+"/mode/set", func(payload string) {
|
||||
apiHandler.SetMode(api.ChargeMode(payload))
|
||||
})
|
||||
|
|
@ -89,7 +90,7 @@ func (m *MQTT) listenSetters(topic string, apiHandler core.LoadPointAPI) {
|
|||
}
|
||||
|
||||
// Run starts the MQTT publisher for the MQTT API
|
||||
func (m *MQTT) Run(site core.SiteAPI, in <-chan util.Param) {
|
||||
func (m *MQTT) Run(site site.API, in <-chan util.Param) {
|
||||
// alive
|
||||
topic := fmt.Sprintf("%s/status", m.root)
|
||||
m.publish(topic, true, "online")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package server
|
||||
|
|
@ -7,7 +8,7 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/evcc-io/evcc/core"
|
||||
"github.com/evcc-io/evcc/core/site"
|
||||
)
|
||||
|
||||
// SocketPath is the unix domain socket path
|
||||
|
|
@ -26,7 +27,7 @@ func remoteIfExists(file string) {
|
|||
}
|
||||
|
||||
// HealthListener attaches listener to unix domain socket and runs listener
|
||||
func HealthListener(site core.SiteAPI) {
|
||||
func HealthListener(site site.API) {
|
||||
remoteIfExists(SocketPath)
|
||||
|
||||
l, err := net.Listen("unix", SocketPath)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue