Fix PENDING state boot notification handling
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 4 Feb 2022 17:45:01 +0000 (18:45 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 4 Feb 2022 17:45:01 +0000 (18:45 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/utils/Constants.ts

index ccc30d0c88dd9a0058b8d22a54948c6dab009db3..3f5b03c12cebf30c53822b6f6b998d08c810a9a4 100644 (file)
@@ -66,8 +66,8 @@ export default class AutomaticTransactionGenerator {
         this.stopConnector(connectorId);
         break;
       }
-      if (!this.chargingStation.isRegistered()) {
-        logger.error(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is not registered');
+      if (!this.chargingStation.isInAcceptedState()) {
+        logger.error(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is in accepted state');
         this.stopConnector(connectorId);
         break;
       }
index 565bdb895af476237584c66c86a6592d4c0e9772..018a6fbeea98fa780b522a2d08c1218011aa6c7f 100644 (file)
@@ -122,10 +122,22 @@ export default class ChargingStation {
     return this?.wsConnection?.readyState === OPEN;
   }
 
-  public isRegistered(): boolean {
+  public isInPendingState(): boolean {
+    return this?.bootNotificationResponse?.status === RegistrationStatus.PENDING;
+  }
+
+  public isInAcceptedState(): boolean {
     return this?.bootNotificationResponse?.status === RegistrationStatus.ACCEPTED;
   }
 
+  public isInRejectedState(): boolean {
+    return this?.bootNotificationResponse?.status === RegistrationStatus.REJECTED;
+  }
+
+  public isRegistered(): boolean {
+    return this.isInAcceptedState() || this.isInPendingState();
+  }
+
   public isChargingStationAvailable(): boolean {
     return this.getConnectorStatus(0).availability === AvailabilityType.OPERATIVE;
   }
@@ -644,12 +656,22 @@ export default class ChargingStation {
       await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel,
         this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion);
     }
-    if (this.isRegistered()) {
+    if (this.isInAcceptedState()) {
       await this.startMessageSequence();
       this.stopped && (this.stopped = false);
       if (this.wsConnectionRestarted && this.isWebSocketConnectionOpened()) {
         this.flushMessageBuffer();
       }
+    } else if (this.isInPendingState()) {
+      // The central server shall issue a triggerMessage to the charging station for the boot notification at the end of its configuration process
+      while (!this.isInAcceptedState()) {
+        await this.startMessageSequence();
+        this.stopped && (this.stopped = false);
+        if (this.wsConnectionRestarted && this.isWebSocketConnectionOpened()) {
+          this.flushMessageBuffer();
+        }
+        await Utils.sleep(Constants.CHARGING_STATION_DEFAULT_START_SEQUENCE_DELAY);
+      }
     } else {
       logger.error(`${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`);
     }
index fa03c535e64dcb87ce08e5ea1c8ee308d2060b7b..81ff70b7dd532cbcb7c35ad72d173707e0573ab5 100644 (file)
@@ -47,7 +47,9 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
 
   public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record<string, unknown>): Promise<void> {
     let result: Record<string, unknown>;
-    if (this.chargingStation.isRegistered()) {
+    if (this.chargingStation.isRegistered() &&
+      !(this.chargingStation.isInPendingState
+        && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION))) {
       if (this.incomingRequestHandlers.has(commandName)) {
         try {
           // Call the method to build the result
@@ -295,7 +297,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
           let authorized = false;
           if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
-              && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
+            && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
             this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag = commandPayload.idTag;
             this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized = true;
             authorized = true;
index 2e43d37697d2e47c603d3b5f312f9d54bef12631..e6503d787283a977fdcc19ee3b5bc2857ec2f129 100644 (file)
@@ -29,6 +29,7 @@ export default class Constants {
   static readonly OCPP_WEBSOCKET_TIMEOUT = 60000; // Ms
   static readonly OCPP_TRIGGER_MESSAGE_DELAY = 2000; // Ms
 
+  static readonly CHARGING_STATION_DEFAULT_START_SEQUENCE_DELAY = 60000; // Ms
   static readonly CHARGING_STATION_DEFAULT_RESET_TIME = 60000; // Ms
   static readonly CHARGING_STATION_ATG_INITIALIZATION_TIME = 1000; // Ms
   static readonly CHARGING_STATION_ATG_DEFAULT_STOP_AFTER_HOURS = 0.25; // Hours