diff --git a/charger/ocpp.go b/charger/ocpp.go index 2526824202..f89125c1e1 100644 --- a/charger/ocpp.go +++ b/charger/ocpp.go @@ -15,6 +15,7 @@ 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" ) @@ -164,8 +165,9 @@ func NewOCPP(id string, connector int, idtag string, idtag: idtag, remoteStart: remoteStart, - chargingRateUnit: types.ChargingRateUnitType(chargingRateUnit), - timeout: timeout, + chargingRateUnit: types.ChargingRateUnitType(chargingRateUnit), + hasRemoteTriggerFeature: true, // assume remote trigger feature is available + timeout: timeout, } c.log.DEBUG.Printf("waiting for chargepoint: %v", connectTimeout) @@ -183,8 +185,89 @@ func NewOCPP(id string, connector int, idtag string, return nil, err } - meterValuesSampledData, meterValuesSampledDataMaxLength, err := c.getConfiguration(cp.ID(), connector) - if err != nil { + var meterValuesSampledData string + meterValuesSampledDataMaxLength := len(strings.Split(desiredMeasurands, ",")) + + rc := make(chan error, 1) + + 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 } diff --git a/charger/ocpp_config.go b/charger/ocpp_config.go deleted file mode 100644 index fd5fa6cafe..0000000000 --- a/charger/ocpp_config.go +++ /dev/null @@ -1,91 +0,0 @@ -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) -}