fix: avoid concurrent ATG startup
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index 2ed3202b887d3482dc1b1ab6c3d77e3cf442edfa..f01034a30029b31e40bbcbb8808326d72203a716 100644 (file)
@@ -8,6 +8,8 @@ import type { JSONSchemaType } from 'ajv';
 import { Client, type FTPResponse } from 'basic-ftp';
 import tar from 'tar';
 
+import { OCPP16Constants } from './OCPP16Constants';
+import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
 import {
   type ChargingStation,
   ChargingStationConfigurationUtils,
@@ -46,7 +48,6 @@ import {
   type OCPP16ClearCacheRequest,
   type OCPP16DataTransferRequest,
   type OCPP16DataTransferResponse,
-  OCPP16DataTransferStatus,
   OCPP16DataTransferVendorId,
   OCPP16DiagnosticsStatus,
   type OCPP16DiagnosticsStatusNotificationRequest,
@@ -83,7 +84,7 @@ import {
   type UnlockConnectorResponse,
 } from '../../../types';
 import { Constants, Utils, logger } from '../../../utils';
-import { OCPP16Constants, OCPP16ServiceUtils, OCPPIncomingRequestService } from '../internal';
+import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService';
 
 const moduleName = 'OCPP16IncomingRequestService';
 
@@ -141,7 +142,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.RESET,
         OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/Reset.json',
+          'assets/json-schemas/ocpp/1.6/Reset.json',
           moduleName,
           'constructor'
         ),
@@ -149,7 +150,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.CLEAR_CACHE,
         OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ClearCache.json',
+          'assets/json-schemas/ocpp/1.6/ClearCache.json',
           moduleName,
           'constructor'
         ),
@@ -157,7 +158,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
         OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json',
+          'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
           moduleName,
           'constructor'
         ),
@@ -165,7 +166,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.GET_CONFIGURATION,
         OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json',
+          'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
           moduleName,
           'constructor'
         ),
@@ -173,7 +174,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
         OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
+          'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
           moduleName,
           'constructor'
         ),
@@ -181,7 +182,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
         OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
+          'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
           moduleName,
           'constructor'
         ),
@@ -189,7 +190,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
         OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
+          'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
           moduleName,
           'constructor'
         ),
@@ -197,7 +198,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
         OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
+          'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
           moduleName,
           'constructor'
         ),
@@ -205,7 +206,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
         OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
+          'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
           moduleName,
           'constructor'
         ),
@@ -213,7 +214,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
         OCPP16ServiceUtils.parseJsonSchemaFile<ChangeAvailabilityRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
+          'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
           moduleName,
           'constructor'
         ),
@@ -221,7 +222,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
         OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
+          'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
           moduleName,
           'constructor'
         ),
@@ -229,7 +230,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
         OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
+          'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
           moduleName,
           'constructor'
         ),
@@ -237,7 +238,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
         OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json',
+          'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
           moduleName,
           'constructor'
         ),
@@ -245,7 +246,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.DATA_TRANSFER,
         OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/DataTransfer.json',
+          'assets/json-schemas/ocpp/1.6/DataTransfer.json',
           moduleName,
           'constructor'
         ),
@@ -253,7 +254,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       [
         OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
         OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
+          'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
           moduleName,
           'constructor'
         ),
@@ -275,7 +276,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     let response: JsonType;
     if (
       chargingStation.getOcppStrictCompliance() === true &&
-      chargingStation.isInPendingState() === true &&
+      chargingStation.inPendingState() === true &&
       (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
         commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
     ) {
@@ -293,7 +294,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     if (
       chargingStation.isRegistered() === true ||
       (chargingStation.getOcppStrictCompliance() === false &&
-        chargingStation.isInUnknownState() === true)
+        chargingStation.inUnknownState() === true)
     ) {
       if (
         this.incomingRequestHandlers.has(commandName) === true &&
@@ -486,9 +487,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     );
     if (!keyToChange) {
       return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
-    } else if (keyToChange && keyToChange.readonly) {
+    } else if (keyToChange?.readonly === true) {
       return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
-    } else if (keyToChange && !keyToChange.readonly) {
+    } else if (keyToChange?.readonly === false) {
       let valueChanged = false;
       if (keyToChange.value !== commandPayload.value) {
         ChargingStationConfigurationUtils.setConfigurationKeyValue(
@@ -797,95 +798,66 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     commandPayload: RemoteStartTransactionRequest
   ): Promise<GenericResponse> {
     const transactionConnectorId = commandPayload.connectorId;
-    if (chargingStation.hasConnector(transactionConnectorId) === true) {
-      const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${
-        chargingStation.stationInfo.chargingStationId
-      }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`;
-      await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+    if (chargingStation.hasConnector(transactionConnectorId) === false) {
+      return this.notifyRemoteStartTransactionRejected(
         chargingStation,
         transactionConnectorId,
-        OCPP16ChargePointStatus.Preparing
+        commandPayload.idTag
       );
-      const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
+    }
+    if (
+      chargingStation.isChargingStationAvailable() === false ||
+      chargingStation.isConnectorAvailable(transactionConnectorId) === false
+    ) {
+      return this.notifyRemoteStartTransactionRejected(
+        chargingStation,
+        transactionConnectorId,
+        commandPayload.idTag
+      );
+    }
+    const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${
+      chargingStation.stationInfo.chargingStationId
+    }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`;
+    await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+      chargingStation,
+      transactionConnectorId,
+      OCPP16ChargePointStatus.Preparing
+    );
+    const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
+    // Check if authorized
+    if (chargingStation.getAuthorizeRemoteTxRequests() === true) {
+      let authorized = false;
       if (
-        chargingStation.isChargingStationAvailable() === true &&
-        chargingStation.isConnectorAvailable(transactionConnectorId) === true
+        chargingStation.getLocalAuthListEnabled() === true &&
+        chargingStation.hasIdTags() === true &&
+        Utils.isNotEmptyString(
+          chargingStation.idTagsCache
+            .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo))
+            ?.find((idTag) => idTag === commandPayload.idTag)
+        )
       ) {
-        // Check if authorized
-        if (chargingStation.getAuthorizeRemoteTxRequests() === true) {
-          let authorized = false;
-          if (
-            chargingStation.getLocalAuthListEnabled() === true &&
-            chargingStation.hasIdTags() === true &&
-            Utils.isNotEmptyString(
-              chargingStation.idTagsCache
-                .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo))
-                ?.find((idTag) => idTag === commandPayload.idTag)
-            )
-          ) {
-            connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
-            connectorStatus.idTagLocalAuthorized = true;
-            authorized = true;
-          } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
-            connectorStatus.authorizeIdTag = commandPayload.idTag;
-            const authorizeResponse: OCPP16AuthorizeResponse =
-              await chargingStation.ocppRequestService.requestHandler<
-                OCPP16AuthorizeRequest,
-                OCPP16AuthorizeResponse
-              >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
-                idTag: commandPayload.idTag,
-              });
-            if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
-              authorized = true;
-            }
-          } else {
-            logger.warn(
-              `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
-            );
-          }
-          if (authorized === true) {
-            // Authorization successful, start transaction
-            if (
-              this.setRemoteStartTransactionChargingProfile(
-                chargingStation,
-                transactionConnectorId,
-                commandPayload.chargingProfile
-              ) === true
-            ) {
-              connectorStatus.transactionRemoteStarted = true;
-              if (
-                (
-                  await chargingStation.ocppRequestService.requestHandler<
-                    OCPP16StartTransactionRequest,
-                    OCPP16StartTransactionResponse
-                  >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
-                    connectorId: transactionConnectorId,
-                    idTag: commandPayload.idTag,
-                  })
-                ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
-              ) {
-                logger.debug(remoteStartTransactionLogMsg);
-                return OCPP16Constants.OCPP_RESPONSE_ACCEPTED;
-              }
-              return this.notifyRemoteStartTransactionRejected(
-                chargingStation,
-                transactionConnectorId,
-                commandPayload.idTag
-              );
-            }
-            return this.notifyRemoteStartTransactionRejected(
-              chargingStation,
-              transactionConnectorId,
-              commandPayload.idTag
-            );
-          }
-          return this.notifyRemoteStartTransactionRejected(
-            chargingStation,
-            transactionConnectorId,
-            commandPayload.idTag
-          );
+        connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
+        connectorStatus.idTagLocalAuthorized = true;
+        authorized = true;
+      } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
+        connectorStatus.authorizeIdTag = commandPayload.idTag;
+        const authorizeResponse: OCPP16AuthorizeResponse =
+          await chargingStation.ocppRequestService.requestHandler<
+            OCPP16AuthorizeRequest,
+            OCPP16AuthorizeResponse
+          >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
+            idTag: commandPayload.idTag,
+          });
+        if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
+          authorized = true;
         }
-        // No authorization check required, start transaction
+      } else {
+        logger.warn(
+          `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
+        );
+      }
+      if (authorized === true) {
+        // Authorization successful, start transaction
         if (
           this.setRemoteStartTransactionChargingProfile(
             chargingStation,
@@ -926,6 +898,35 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         commandPayload.idTag
       );
     }
+    // No authorization check required, start transaction
+    if (
+      this.setRemoteStartTransactionChargingProfile(
+        chargingStation,
+        transactionConnectorId,
+        commandPayload.chargingProfile
+      ) === true
+    ) {
+      connectorStatus.transactionRemoteStarted = true;
+      if (
+        (
+          await chargingStation.ocppRequestService.requestHandler<
+            OCPP16StartTransactionRequest,
+            OCPP16StartTransactionResponse
+          >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
+            connectorId: transactionConnectorId,
+            idTag: commandPayload.idTag,
+          })
+        ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
+      ) {
+        logger.debug(remoteStartTransactionLogMsg);
+        return OCPP16Constants.OCPP_RESPONSE_ACCEPTED;
+      }
+      return this.notifyRemoteStartTransactionRejected(
+        chargingStation,
+        transactionConnectorId,
+        commandPayload.idTag
+      );
+    }
     return this.notifyRemoteStartTransactionRejected(
       chargingStation,
       transactionConnectorId,
@@ -1242,7 +1243,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       let ftpClient: Client;
       try {
         const logFiles = fs
-          .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'))
+          .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'))
           .filter((file) => file.endsWith('.log'))
           .map((file) => path.join('./', file));
         const diagnosticsArchive = `${chargingStation.stationInfo.chargingStationId}_logs.tar.gz`;
@@ -1280,7 +1281,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
           });
           uploadResponse = await ftpClient.uploadFrom(
             path.join(
-              path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'),
+              path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
               diagnosticsArchive
             ),
             `${uri.pathname}${diagnosticsArchive}`
@@ -1486,13 +1487,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
   ): OCPP16DataTransferResponse {
     try {
       if (Object.values(OCPP16DataTransferVendorId).includes(commandPayload.vendorId)) {
-        return {
-          status: OCPP16DataTransferStatus.ACCEPTED,
-        };
+        return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_ACCEPTED;
       }
-      return {
-        status: OCPP16DataTransferStatus.UNKNOWN_VENDOR_ID,
-      };
+      return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_UNKNOWN_VENDOR_ID;
     } catch (error) {
       return this.handleIncomingRequestError(
         chargingStation,