Ocpp: modularise setup (#15369)
This commit is contained in:
parent
95ad4346fd
commit
e466564c56
2 changed files with 98 additions and 90 deletions
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/evcc-io/evcc/core/loadpoint"
|
"github.com/evcc-io/evcc/core/loadpoint"
|
||||||
"github.com/evcc-io/evcc/util"
|
"github.com/evcc-io/evcc/util"
|
||||||
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
|
||||||
"github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger"
|
|
||||||
"github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging"
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging"
|
||||||
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
|
||||||
)
|
)
|
||||||
|
|
@ -160,10 +159,11 @@ func NewOCPP(id string, connector int, idtag string,
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &OCPP{
|
c := &OCPP{
|
||||||
log: log,
|
log: log,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
idtag: idtag,
|
idtag: idtag,
|
||||||
remoteStart: remoteStart,
|
remoteStart: remoteStart,
|
||||||
|
|
||||||
chargingRateUnit: types.ChargingRateUnitType(chargingRateUnit),
|
chargingRateUnit: types.ChargingRateUnitType(chargingRateUnit),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
}
|
}
|
||||||
|
|
@ -179,91 +179,8 @@ func NewOCPP(id string, connector int, idtag string,
|
||||||
// fix timing issue in EVBox when switching OCPP protocol version
|
// fix timing issue in EVBox when switching OCPP protocol version
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
var rc = make(chan error, 1)
|
meterValuesSampledData, meterValuesSampledDataMaxLength, err := c.getConfiguration(cp.ID(), connector)
|
||||||
|
if err != nil {
|
||||||
meterValuesSampledData := ""
|
|
||||||
meterValuesSampledDataMaxLength := len(strings.Split(desiredMeasurands, ","))
|
|
||||||
|
|
||||||
c.hasRemoteTriggerFeature = true // assume remote trigger feature is available
|
|
||||||
|
|
||||||
err = ocpp.Instance().GetConfiguration(cp.ID(), func(resp *core.GetConfigurationConfirmation, err error) {
|
|
||||||
if err == nil {
|
|
||||||
for _, opt := range resp.ConfigurationKey {
|
|
||||||
if opt.Value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch opt.Key {
|
|
||||||
case ocpp.KeyChargeProfileMaxStackLevel:
|
|
||||||
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
|
||||||
c.stackLevel = val
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyChargingScheduleAllowedChargingRateUnit:
|
|
||||||
if *opt.Value == "Power" || *opt.Value == "W" { // "W" is not allowed by spec but used by some CPs
|
|
||||||
c.chargingRateUnit = types.ChargingRateUnitWatts
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyConnectorSwitch3to1PhaseSupported:
|
|
||||||
var val bool
|
|
||||||
if val, err = strconv.ParseBool(*opt.Value); err == nil {
|
|
||||||
c.phaseSwitching = val
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyMaxChargingProfilesInstalled:
|
|
||||||
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
|
||||||
c.chargingProfileId = val
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyMeterValuesSampledData:
|
|
||||||
if opt.Readonly {
|
|
||||||
meterValuesSampledDataMaxLength = 0
|
|
||||||
}
|
|
||||||
meterValuesSampledData = *opt.Value
|
|
||||||
|
|
||||||
case ocpp.KeyMeterValuesSampledDataMaxLength:
|
|
||||||
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
|
||||||
meterValuesSampledDataMaxLength = val
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyNumberOfConnectors:
|
|
||||||
var val int
|
|
||||||
if val, err = strconv.Atoi(*opt.Value); err == nil && connector > val {
|
|
||||||
err = fmt.Errorf("connector %d exceeds max available connectors: %d", connector, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeySupportedFeatureProfiles:
|
|
||||||
if !c.hasProperty(*opt.Value, smartcharging.ProfileName) {
|
|
||||||
c.log.WARN.Printf("the required SmartCharging feature profile is not indicated as supported")
|
|
||||||
}
|
|
||||||
// correct the availability assumption of RemoteTrigger only in case of a valid looking FeatureProfile list
|
|
||||||
if c.hasProperty(*opt.Value, core.ProfileName) {
|
|
||||||
c.hasRemoteTriggerFeature = c.hasProperty(*opt.Value, remotetrigger.ProfileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// vendor-specific keys
|
|
||||||
case ocpp.KeyAlfenPlugAndChargeIdentifier:
|
|
||||||
if c.idtag == defaultIdTag {
|
|
||||||
c.idtag = *opt.Value
|
|
||||||
c.log.DEBUG.Printf("overriding default `idTag` with Alfen-specific value: %s", c.idtag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ocpp.KeyEvBoxSupportedMeasurands:
|
|
||||||
if meterValues == "" {
|
|
||||||
meterValues = *opt.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc <- err
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
if err := c.wait(err, rc); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
91
charger/ocpp_config.go
Normal file
91
charger/ocpp_config.go
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package charger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/evcc-io/evcc/charger/ocpp"
|
||||||
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
|
||||||
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger"
|
||||||
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging"
|
||||||
|
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *OCPP) getConfiguration(id string, connector int) (string, int, error) {
|
||||||
|
var meterValuesSampledData string
|
||||||
|
meterValuesSampledDataMaxLength := len(strings.Split(desiredMeasurands, ","))
|
||||||
|
|
||||||
|
rc := make(chan error, 1)
|
||||||
|
|
||||||
|
err := ocpp.Instance().GetConfiguration(id, func(resp *core.GetConfigurationConfirmation, err error) {
|
||||||
|
if err == nil {
|
||||||
|
for _, opt := range resp.ConfigurationKey {
|
||||||
|
if opt.Value == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch opt.Key {
|
||||||
|
case ocpp.KeyChargeProfileMaxStackLevel:
|
||||||
|
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
||||||
|
c.stackLevel = val
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeyChargingScheduleAllowedChargingRateUnit:
|
||||||
|
if *opt.Value == "Power" || *opt.Value == "W" { // "W" is not allowed by spec but used by some CPs
|
||||||
|
c.chargingRateUnit = types.ChargingRateUnitWatts
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeyConnectorSwitch3to1PhaseSupported:
|
||||||
|
var val bool
|
||||||
|
if val, err = strconv.ParseBool(*opt.Value); err == nil {
|
||||||
|
c.phaseSwitching = val
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeyMaxChargingProfilesInstalled:
|
||||||
|
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
||||||
|
c.chargingProfileId = val
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeyMeterValuesSampledData:
|
||||||
|
if opt.Readonly {
|
||||||
|
meterValuesSampledDataMaxLength = 0
|
||||||
|
}
|
||||||
|
meterValuesSampledData = *opt.Value
|
||||||
|
|
||||||
|
case ocpp.KeyMeterValuesSampledDataMaxLength:
|
||||||
|
if val, err := strconv.Atoi(*opt.Value); err == nil {
|
||||||
|
meterValuesSampledDataMaxLength = val
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeyNumberOfConnectors:
|
||||||
|
var val int
|
||||||
|
if val, err = strconv.Atoi(*opt.Value); err == nil && connector > val {
|
||||||
|
err = fmt.Errorf("connector %d exceeds max available connectors: %d", connector, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
case ocpp.KeySupportedFeatureProfiles:
|
||||||
|
if !c.hasProperty(*opt.Value, smartcharging.ProfileName) {
|
||||||
|
err = fmt.Errorf("the mandatory SmartCharging profile is not supported")
|
||||||
|
}
|
||||||
|
c.hasRemoteTriggerFeature = c.hasProperty(*opt.Value, remotetrigger.ProfileName)
|
||||||
|
|
||||||
|
// vendor-specific keys
|
||||||
|
case ocpp.KeyAlfenPlugAndChargeIdentifier:
|
||||||
|
if c.idtag == defaultIdTag {
|
||||||
|
c.idtag = *opt.Value
|
||||||
|
c.log.DEBUG.Printf("overriding default `idTag` with Alfen-specific value: %s", c.idtag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc <- err
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
return meterValuesSampledData, meterValuesSampledDataMaxLength, c.wait(err, rc)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue