fix(simulator): lookup OCPP configuration key case insensitively
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index b9f8368b36aa4bf882154efe0fd2dc6caef29031..b1df54b787b7f826d4b1863266af524031742704 100644 (file)
@@ -1,8 +1,8 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
-import fs from 'fs';
-import path from 'path';
-import { URL, fileURLToPath } from 'url';
+import fs from 'node:fs';
+import path from 'node:path';
+import { URL, fileURLToPath } from 'node:url';
 
 import type { JSONSchemaType } from 'ajv';
 import { Client, type FTPResponse } from 'basic-ftp';
@@ -140,84 +140,114 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>([
       [
         OCPP16IncomingRequestCommand.RESET,
-        this.parseJsonSchemaFile<ResetRequest>('../../../assets/json-schemas/ocpp/1.6/Reset.json'),
+        OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/Reset.json',
+          moduleName,
+          'constructor'
+        ),
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CACHE,
-        this.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ClearCache.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/ClearCache.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-        this.parseJsonSchemaFile<UnlockConnectorRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-        this.parseJsonSchemaFile<GetConfigurationRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-        this.parseJsonSchemaFile<ChangeConfigurationRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-        this.parseJsonSchemaFile<GetDiagnosticsRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-        this.parseJsonSchemaFile<SetChargingProfileRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        this.parseJsonSchemaFile<ClearChargingProfileRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-        this.parseJsonSchemaFile<ChangeAvailabilityRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<ChangeAvailabilityRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-        this.parseJsonSchemaFile<RemoteStartTransactionRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-        this.parseJsonSchemaFile<RemoteStopTransactionRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        this.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.DATA_TRANSFER,
-        this.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/DataTransfer.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/DataTransfer.json',
+          moduleName,
+          'constructor'
         ),
       ],
       [
         OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
-        this.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
-          '../../../assets/json-schemas/ocpp/1.6/UpdateFirmware.json'
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
+          '../../../assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
+          moduleName,
+          'constructor'
         ),
       ],
     ]);
@@ -330,18 +360,16 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     chargingStation: ChargingStation,
     commandPayload: ResetRequest
   ): GenericResponse {
-    this.asyncResource
-      .runInAsyncScope(
-        chargingStation.reset.bind(chargingStation) as (
-          this: ChargingStation,
-          ...args: any[]
-        ) => Promise<void>,
-        chargingStation,
-        `${commandPayload.type}Reset` as OCPP16StopTransactionReason
-      )
-      .catch(() => {
-        /* This is intentional */
-      });
+    this.runInAsyncScope(
+      chargingStation.reset.bind(chargingStation) as (
+        this: ChargingStation,
+        ...args: any[]
+      ) => Promise<void>,
+      chargingStation,
+      `${commandPayload.type}Reset` as OCPP16StopTransactionReason
+    ).catch(() => {
+      /* This is intentional */
+    });
     logger.info(
       `${chargingStation.logPrefix()} ${
         commandPayload.type
@@ -397,7 +425,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   ): GetConfigurationResponse {
     const configurationKey: OCPPConfigurationKey[] = [];
     const unknownKey: string[] = [];
-    if (Utils.isEmptyArray(commandPayload.key) === true) {
+    if (Utils.isUndefined(commandPayload.key) === true) {
       for (const configuration of chargingStation.ocppConfiguration.configurationKey) {
         if (Utils.isUndefined(configuration.visible) === true) {
           configuration.visible = true;
@@ -411,11 +439,12 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           value: configuration.value,
         });
       }
-    } else {
+    } else if (Utils.isNotEmptyArray(commandPayload.key) === true) {
       for (const key of commandPayload.key) {
         const keyFound = ChargingStationConfigurationUtils.getConfigurationKey(
           chargingStation,
-          key
+          key,
+          true
         );
         if (keyFound) {
           if (Utils.isUndefined(keyFound.visible) === true) {
@@ -574,7 +603,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId);
     if (
       !Utils.isNullOrUndefined(commandPayload.connectorId) &&
-      !Utils.isEmptyArray(connectorStatus?.chargingProfiles)
+      Utils.isNotEmptyArray(connectorStatus?.chargingProfiles)
     ) {
       connectorStatus.chargingProfiles = [];
       logger.debug(
@@ -588,7 +617,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       let clearedCP = false;
       for (const connectorId of chargingStation.connectors.keys()) {
         if (
-          !Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)
+          Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)
         ) {
           chargingStation
             .getConnectorStatus(connectorId)
@@ -719,7 +748,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           if (
             chargingStation.getLocalAuthListEnabled() === true &&
             chargingStation.hasAuthorizedTags() === true &&
-            !Utils.isEmptyString(
+            Utils.isNotEmptyString(
               chargingStation.authorizedTagsCache
                 .getAuthorizedTags(
                   ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo)
@@ -950,18 +979,16 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     const retrieveDate = Utils.convertToDate(commandPayload.retrieveDate);
     const now = Date.now();
     if (retrieveDate?.getTime() <= now) {
-      this.asyncResource
-        .runInAsyncScope(
-          this.updateFirmware.bind(this) as (
-            this: OCPP16IncomingRequestService,
-            ...args: any[]
-          ) => Promise<void>,
-          this,
-          chargingStation
-        )
-        .catch(() => {
-          /* This is intentional */
-        });
+      this.runInAsyncScope(
+        this.updateFirmware.bind(this) as (
+          this: OCPP16IncomingRequestService,
+          ...args: any[]
+        ) => Promise<void>,
+        this,
+        chargingStation
+      ).catch(() => {
+        /* This is intentional */
+      });
     } else {
       setTimeout(() => {
         this.updateFirmware(chargingStation).catch(() => {
@@ -997,7 +1024,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     }
     if (
       chargingStation.stationInfo?.firmwareUpgrade?.failureStatus &&
-      !Utils.isEmptyString(chargingStation.stationInfo?.firmwareUpgrade?.failureStatus)
+      Utils.isNotEmptyString(chargingStation.stationInfo?.firmwareUpgrade?.failureStatus)
     ) {
       await chargingStation.ocppRequestService.requestHandler<
         OCPP16FirmwareStatusNotificationRequest,
@@ -1065,9 +1092,9 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         ftpClient = new Client();
         const accessResponse = await ftpClient.access({
           host: uri.host,
-          ...(!Utils.isEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
-          ...(!Utils.isEmptyString(uri.username) && { user: uri.username }),
-          ...(!Utils.isEmptyString(uri.password) && { password: uri.password }),
+          ...(Utils.isNotEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
+          ...(Utils.isNotEmptyString(uri.username) && { user: uri.username }),
+          ...(Utils.isNotEmptyString(uri.password) && { password: uri.password }),
         });
         let uploadResponse: FTPResponse;
         if (accessResponse.code === 220) {
@@ -1300,13 +1327,4 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       );
     }
   }
-
-  private parseJsonSchemaFile<T extends JsonType>(relativePath: string): JSONSchemaType<T> {
-    return JSON.parse(
-      fs.readFileSync(
-        path.resolve(path.dirname(fileURLToPath(import.meta.url)), relativePath),
-        'utf8'
-      )
-    ) as JSONSchemaType<T>;
-  }
 }