diff --git a/charger/ocpp.go b/charger/ocpp.go index eb2cf72397..62640b4c9f 100644 --- a/charger/ocpp.go +++ b/charger/ocpp.go @@ -15,7 +15,6 @@ import ( "github.com/evcc-io/evcc/core/loadpoint" "github.com/evcc-io/evcc/util" "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" ) @@ -160,10 +159,11 @@ func NewOCPP(id string, connector int, idtag string, } c := &OCPP{ - log: log, - conn: conn, - idtag: idtag, - remoteStart: remoteStart, + log: log, + conn: conn, + idtag: idtag, + remoteStart: remoteStart, + chargingRateUnit: types.ChargingRateUnitType(chargingRateUnit), timeout: timeout, } @@ -179,91 +179,8 @@ func NewOCPP(id string, connector int, idtag string, // fix timing issue in EVBox when switching OCPP protocol version time.Sleep(time.Second) - var rc = make(chan error, 1) - - 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 { + meterValuesSampledData, meterValuesSampledDataMaxLength, err := c.getConfiguration(cp.ID(), connector) + if err != nil { return nil, err } diff --git a/charger/ocpp_config.go b/charger/ocpp_config.go new file mode 100644 index 0000000000..fd5fa6cafe --- /dev/null +++ b/charger/ocpp_config.go @@ -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) +}