From 36f6a92e3ab0a4a452da57aad6510bda259296ce Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 13 Jun 2021 21:47:35 +0200 Subject: [PATCH] Complete AuthorizeRemoteTxRequests support in remote start transaction MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- README.md | 5 ++- src/charging-station/ChargingStation.ts | 13 ++++-- .../ocpp/1.6/OCCP16IncomingRequestService.ts | 41 ++++++++++++++----- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 09c06140..0a24123d 100644 --- a/README.md +++ b/README.md @@ -233,10 +233,11 @@ All kind of OCPP parameters are supported in a charging station template. The li - :x: StopTransactionOnInvalidId (type: boolean) (units: -) - :x: StopTxnAlignedData (type: CSL) (units: -) - :x: StopTxnSampledData (type: CSL) (units: -) -- :x: SupportedFeatureProfiles (type: CSL) (units: -) +- :white_check_mark: SupportedFeatureProfiles (type: CSL) (units: -) - :x: TransactionMessageAttempts (type: integer) (units: times) - :x: TransactionMessageRetryInterval (type: integer) (units: seconds) - :x: UnlockConnectorOnEVSideDisconnect (type: boolean) (units: -) +- :white_check_mark: WebSocketPingInterval (type: integer) (units: seconds) #### Firmware Management Profile @@ -244,7 +245,7 @@ All kind of OCPP parameters are supported in a charging station template. The li #### Local Auth List Management Profile -- :x: LocalAuthListEnabled (type: boolean) (units: -) +- :white_check_mark: LocalAuthListEnabled (type: boolean) (units: -) - :x: LocalAuthListMaxLength (type: integer) (units: -) - :x: SendLocalListMaxLength (type: integer) (units: -) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index feffa05d..10806bd2 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -503,13 +503,13 @@ export default class ChargingStation { break; } // OCPP parameters + if (!this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)) { + this.addConfigurationKey(StandardParametersKey.SupportedFeatureProfiles, `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.Local_Auth_List_Management},${SupportedFeatureProfiles.Smart_Charging}`); + } this.addConfigurationKey(StandardParametersKey.NumberOfConnectors, this.getNumberOfConnectors().toString(), true); if (!this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData)) { this.addConfigurationKey(StandardParametersKey.MeterValuesSampledData, MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER); } - if (!this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)) { - this.addConfigurationKey(StandardParametersKey.SupportedFeatureProfiles, SupportedFeatureProfiles.Core); - } if (!this.getConfigurationKey(StandardParametersKey.ConnectorPhaseRotation)) { const connectorPhaseRotation = []; for (const connector in this.connectors) { @@ -527,6 +527,13 @@ export default class ChargingStation { } this.addConfigurationKey(StandardParametersKey.ConnectorPhaseRotation, connectorPhaseRotation.toString()); } + if (!this.getConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests)) { + this.addConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests, 'true'); + } + if (!this.getConfigurationKey(StandardParametersKey.LocalAuthListEnabled) + && this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles).value.includes(SupportedFeatureProfiles.Local_Auth_List_Management)) { + this.addConfigurationKey(StandardParametersKey.LocalAuthListEnabled, 'false'); + } this.stationInfo.powerDivider = this.getPowerDivider(); if (this.getEnableStatistics()) { this.performanceStatistics = new PerformanceStatistics(this.stationInfo.chargingStationId); diff --git a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts index ba1f2f7e..7c32cb78 100644 --- a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts @@ -255,40 +255,59 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise { - const transactionConnectorID: number = commandPayload.connectorId ? commandPayload.connectorId : 1; + const transactionConnectorID: number = commandPayload.connectorId ?? 1; + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING); + this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.PREPARING; if (this.chargingStation.isChargingStationAvailable() && this.chargingStation.isConnectorAvailable(transactionConnectorID)) { - if (this.chargingStation.getAuthorizeRemoteTxRequests() && this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()) { + if (this.chargingStation.getAuthorizeRemoteTxRequests()) { + let authorized = false; // Check if authorized - if (this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) { - await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING); - this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.PREPARING; + if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags() + && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) { + authorized = true; if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { this.chargingStation.setChargingProfile(transactionConnectorID, commandPayload.chargingProfile); - logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at start transaction, dump their stack: %j`, this.chargingStation.getConnector(transactionConnectorID).chargingProfiles); + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnector(transactionConnectorID).chargingProfiles); } else if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.AVAILABLE; + logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${commandPayload.chargingProfile.chargingProfilePurpose} charging profile(s) at remote start transaction`); return Constants.OCPP_RESPONSE_REJECTED; } - // Authorization successful start transaction + } + if (!authorized) { + const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(commandPayload.idTag); + if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { + authorized = true; + } + } + if (authorized) { + // Authorization successful, start transaction await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorID, commandPayload.idTag); logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_ACCEPTED; } + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.AVAILABLE; logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_REJECTED; } - await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING); - this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.PREPARING; if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { this.chargingStation.setChargingProfile(transactionConnectorID, commandPayload.chargingProfile); - logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at start transaction, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles); + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles); } else if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.AVAILABLE; + logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${commandPayload.chargingProfile.chargingProfilePurpose} charging profile(s) at remote start transaction`); return Constants.OCPP_RESPONSE_REJECTED; } - // No local authorization check required => start transaction + // No authorization check required, start transaction await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorID, commandPayload.idTag); logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_ACCEPTED; } + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.AVAILABLE; logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_REJECTED; } -- 2.34.1