Add more sanity checks at remote start transaction
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 6 Oct 2021 14:30:04 +0000 (16:30 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 6 Oct 2021 14:30:04 +0000 (16:30 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/types/Connectors.ts

index 6e57931b7f17e1469c0f1be2ab457cbf21935b61..49c95d1e407600e33050a4cdbf32e3dc4975aa7b 100644 (file)
@@ -400,9 +400,12 @@ export default class ChargingStation {
     !cpReplaced && this.getConnectorStatus(connectorId).chargingProfiles?.push(cp);
   }
 
-  public resetTransactionOnConnector(connectorId: number): void {
-    this.getConnectorStatus(connectorId).authorized = false;
+  public resetConnectorStatus(connectorId: number): void {
+    this.getConnectorStatus(connectorId).idTagLocalAuthorized = false;
+    this.getConnectorStatus(connectorId).idTagAuthorized = false;
+    this.getConnectorStatus(connectorId).transactionRemoteStarted = false;
     this.getConnectorStatus(connectorId).transactionStarted = false;
+    delete this.getConnectorStatus(connectorId).localAuthorizeIdTag;
     delete this.getConnectorStatus(connectorId).authorizeIdTag;
     delete this.getConnectorStatus(connectorId).transactionId;
     delete this.getConnectorStatus(connectorId).transactionIdTag;
@@ -533,7 +536,7 @@ export default class ChargingStation {
     // Initialize transaction attributes on connectors
     for (const connectorId of this.connectors.keys()) {
       if (connectorId > 0 && !this.getConnectorStatus(connectorId)?.transactionStarted) {
-        this.initTransactionAttributesOnConnector(connectorId);
+        this.initializeConnectorStatus(connectorId);
       }
     }
     switch (this.getOCPPVersion()) {
@@ -1050,8 +1053,10 @@ export default class ChargingStation {
     }
   }
 
-  private initTransactionAttributesOnConnector(connectorId: number): void {
-    this.getConnectorStatus(connectorId).authorized = false;
+  private initializeConnectorStatus(connectorId: number): void {
+    this.getConnectorStatus(connectorId).idTagLocalAuthorized = false;
+    this.getConnectorStatus(connectorId).idTagAuthorized = false;
+    this.getConnectorStatus(connectorId).transactionRemoteStarted = false;
     this.getConnectorStatus(connectorId).transactionStarted = false;
     this.getConnectorStatus(connectorId).energyActiveImportRegisterValue = 0;
     this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
index 94f98e8b0843603eea1ea8e52f8d28b85ad1ed2e..1aa5a9bb2ddedb1f416c6dfbff13ac5a99cc3440 100644 (file)
@@ -293,19 +293,20 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           let authorized = false;
           if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
               && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
+            this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag = commandPayload.idTag;
+            this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized = true;
             authorized = true;
           }
-          if (!authorized || (authorized && this.chargingStation.getMayAuthorizeAtRemoteStart())) {
+          if (!authorized && this.chargingStation.getMayAuthorizeAtRemoteStart()) {
             const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(transactionConnectorId, commandPayload.idTag);
             if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
               authorized = true;
-            } else {
-              authorized = false;
             }
           }
           if (authorized) {
             // Authorization successful, start transaction
             if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
+              this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
               if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
                 logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
                 return Constants.OCPP_RESPONSE_ACCEPTED;
@@ -318,6 +319,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         }
         // No authorization check required, start transaction
         if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
+          this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
           if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
             logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
             return Constants.OCPP_RESPONSE_ACCEPTED;
index cc334aee41c4c67426236d9d429301c04143816f..2c2b80488954520555decfa8fa7eaedd156f0387 100644 (file)
@@ -67,10 +67,10 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       }
     }
     if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
-      this.chargingStation.getConnectorStatus(authorizeConnectorId).authorized = true;
+      this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true;
       logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`);
     } else {
-      this.chargingStation.getConnectorStatus(authorizeConnectorId).authorized = false;
+      this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
       delete this.chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag;
       logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`);
     }
@@ -90,8 +90,28 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString());
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId).authorized && this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag) {
+    if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
+      && this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized) {
+      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not local authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+      await this.resetConnectorOnStartTransactionError(connectorId);
+      return;
+    }
+    if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
+      && this.chargingStation.getMayAuthorizeAtRemoteStart() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
+      && !this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized) {
+      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+      await this.resetConnectorOnStartTransactionError(connectorId);
+      return;
+    }
+    if (this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized && this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag) {
       logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the authorize request one ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+      await this.resetConnectorOnStartTransactionError(connectorId);
+      return;
+    }
+    if (this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
+      && this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== requestPayload.idTag) {
+      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the local authorized one ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+      await this.resetConnectorOnStartTransactionError(connectorId);
       return;
     }
     if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
@@ -127,11 +147,15 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       this.chargingStation.startMeterValues(connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
     } else {
       logger.warn(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
-      this.chargingStation.resetTransactionOnConnector(connectorId);
-      if (this.chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE) {
-        await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
-        this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
-      }
+      await this.resetConnectorOnStartTransactionError(connectorId);
+    }
+  }
+
+  private async resetConnectorOnStartTransactionError(connectorId: number): Promise<void> {
+    this.chargingStation.resetConnectorStatus(connectorId);
+    if (this.chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE) {
+      await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
+      this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
     }
   }
 
@@ -162,7 +186,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
         this.chargingStation.stationInfo.powerDivider--;
       }
       logger.info(this.chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString());
-      this.chargingStation.resetTransactionOnConnector(transactionConnectorId);
+      this.chargingStation.resetConnectorStatus(transactionConnectorId);
     } else {
       logger.warn(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
     }
index d2c262409a3b9d4260daa209ad83084edd7c209f..027ac645d7f22336e399b79d0793f7ef85b51ac4 100644 (file)
@@ -14,7 +14,10 @@ export interface ConnectorStatus {
   status?: ChargePointStatus;
   MeterValues: SampledValueTemplate[];
   authorizeIdTag?: string;
-  authorized?: boolean;
+  idTagAuthorized?: boolean;
+  localAuthorizeIdTag?: string;
+  idTagLocalAuthorized?: boolean;
+  transactionRemoteStarted?: boolean;
   transactionStarted?: boolean;
   transactionId?: number;
   transactionSetInterval?: NodeJS.Timeout;