refactor(simulator): introduce HTTP methods enum
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 79cf45b8a60166c3caa9cef671f921031956142d..23724e79014584cdf9d5dc042cd29b0fcce0f249 100644 (file)
@@ -4,96 +4,101 @@ import crypto from 'node:crypto';
 import fs from 'node:fs';
 import path from 'node:path';
 import { URL } from 'node:url';
-import { parentPort } from 'worker_threads';
+import { parentPort } from 'node:worker_threads';
 
 import merge from 'just-merge';
 import WebSocket, { type RawData } from 'ws';
 
-import AuthorizedTagsCache from './AuthorizedTagsCache';
-import AutomaticTransactionGenerator from './AutomaticTransactionGenerator';
-import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
-import { ChargingStationUtils } from './ChargingStationUtils';
-import ChargingStationWorkerBroadcastChannel from './ChargingStationWorkerBroadcastChannel';
-import { MessageChannelUtils } from './MessageChannelUtils';
-import OCPP16IncomingRequestService from './ocpp/1.6/OCPP16IncomingRequestService';
-import OCPP16RequestService from './ocpp/1.6/OCPP16RequestService';
-import OCPP16ResponseService from './ocpp/1.6/OCPP16ResponseService';
-import { OCPP16ServiceUtils } from './ocpp/1.6/OCPP16ServiceUtils';
-import OCPP20IncomingRequestService from './ocpp/2.0/OCPP20IncomingRequestService';
-import OCPP20RequestService from './ocpp/2.0/OCPP20RequestService';
-import OCPP20ResponseService from './ocpp/2.0/OCPP20ResponseService';
-import type OCPPIncomingRequestService from './ocpp/OCPPIncomingRequestService';
-import type OCPPRequestService from './ocpp/OCPPRequestService';
-import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
-import SharedLRUCache from './SharedLRUCache';
-import BaseError from '../exception/BaseError';
-import OCPPError from '../exception/OCPPError';
-import PerformanceStatistics from '../performance/PerformanceStatistics';
-import type { AutomaticTransactionGeneratorConfiguration } from '../types/AutomaticTransactionGenerator';
-import type { ChargingStationConfiguration } from '../types/ChargingStationConfiguration';
-import type { ChargingStationInfo } from '../types/ChargingStationInfo';
-import type { ChargingStationOcppConfiguration } from '../types/ChargingStationOcppConfiguration';
 import {
-  type ChargingStationTemplate,
-  CurrentType,
-  PowerUnits,
-  type WsOptions,
-} from '../types/ChargingStationTemplate';
-import { SupervisionUrlDistribution } from '../types/ConfigurationData';
-import type { ConnectorStatus } from '../types/ConnectorStatus';
-import { FileType } from '../types/FileType';
-import type { JsonType } from '../types/JsonType';
+  AuthorizedTagsCache,
+  AutomaticTransactionGenerator,
+  ChargingStationConfigurationUtils,
+  ChargingStationUtils,
+  ChargingStationWorkerBroadcastChannel,
+  MessageChannelUtils,
+  SharedLRUCache,
+} from './internal';
 import {
-  ConnectorPhaseRotation,
-  StandardParametersKey,
-  SupportedFeatureProfiles,
-  VendorDefaultParametersKey,
-} from '../types/ocpp/Configuration';
-import { ConnectorStatusEnum } from '../types/ocpp/ConnectorStatusEnum';
-import { ErrorType } from '../types/ocpp/ErrorType';
-import { MessageType } from '../types/ocpp/MessageType';
-import { MeterValue, MeterValueMeasurand } from '../types/ocpp/MeterValues';
-import { OCPPVersion } from '../types/ocpp/OCPPVersion';
+  // OCPP16IncomingRequestService,
+  OCPP16RequestService,
+  // OCPP16ResponseService,
+  OCPP16ServiceUtils,
+  OCPP20IncomingRequestService,
+  OCPP20RequestService,
+  // OCPP20ResponseService,
+  type OCPPIncomingRequestService,
+  type OCPPRequestService,
+  // OCPPServiceUtils,
+} from './ocpp';
+import { OCPP16IncomingRequestService } from './ocpp/1.6/OCPP16IncomingRequestService';
+import { OCPP16ResponseService } from './ocpp/1.6/OCPP16ResponseService';
+import { OCPP20ResponseService } from './ocpp/2.0/OCPP20ResponseService';
+import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
+import { BaseError, OCPPError } from '../exception';
+import { PerformanceStatistics } from '../performance';
 import {
+  type AutomaticTransactionGeneratorConfiguration,
   AvailabilityType,
   type BootNotificationRequest,
+  type BootNotificationResponse,
   type CachedRequest,
+  type ChargingStationConfiguration,
+  type ChargingStationInfo,
+  type ChargingStationOcppConfiguration,
+  type ChargingStationTemplate,
+  ConnectorPhaseRotation,
+  ConnectorStatus,
+  ConnectorStatusEnum,
+  CurrentType,
   type ErrorCallback,
+  type ErrorResponse,
+  ErrorType,
+  FileType,
   FirmwareStatus,
   type FirmwareStatusNotificationRequest,
+  type FirmwareStatusNotificationResponse,
+  type FirmwareUpgrade,
   type HeartbeatRequest,
+  type HeartbeatResponse,
   type IncomingRequest,
-  IncomingRequestCommand,
+  type IncomingRequestCommand,
+  type JsonType,
+  MessageType,
+  type MeterValue,
+  MeterValueMeasurand,
   type MeterValuesRequest,
+  type MeterValuesResponse,
+  OCPPVersion,
   type OutgoingRequest,
+  PowerUnits,
+  RegistrationStatusEnumType,
   RequestCommand,
+  type Response,
   type ResponseCallback,
+  StandardParametersKey,
   type StatusNotificationRequest,
-} from '../types/ocpp/Requests';
-import {
-  type BootNotificationResponse,
-  type ErrorResponse,
-  type FirmwareStatusNotificationResponse,
-  type HeartbeatResponse,
-  type MeterValuesResponse,
-  RegistrationStatusEnumType,
-  type Response,
   type StatusNotificationResponse,
-} from '../types/ocpp/Responses';
-import {
   StopTransactionReason,
   type StopTransactionRequest,
   type StopTransactionResponse,
-} from '../types/ocpp/Transaction';
-import { WSError, WebSocketCloseEventStatusCode } from '../types/WebSocket';
-import Configuration from '../utils/Configuration';
-import Constants from '../utils/Constants';
-import { ACElectricUtils, DCElectricUtils } from '../utils/ElectricUtils';
-import FileUtils from '../utils/FileUtils';
-import logger from '../utils/Logger';
-import Utils from '../utils/Utils';
-
-export default class ChargingStation {
+  SupervisionUrlDistribution,
+  SupportedFeatureProfiles,
+  VendorParametersKey,
+  type WSError,
+  WebSocketCloseEventStatusCode,
+  type WsOptions,
+} from '../types';
+import {
+  ACElectricUtils,
+  Configuration,
+  Constants,
+  DCElectricUtils,
+  FileUtils,
+  Utils,
+  logger,
+} from '../utils';
+
+export class ChargingStation {
   public readonly index: number;
   public readonly templateFile: string;
   public stationInfo!: ChargingStationInfo;
@@ -160,7 +165,7 @@ export default class ChargingStation {
   public logPrefix = (): string => {
     return Utils.logPrefix(
       ` ${
-        (!Utils.isEmptyString(this?.stationInfo?.chargingStationId) &&
+        (Utils.isNotEmptyString(this?.stationInfo?.chargingStationId) &&
           this?.stationInfo?.chargingStationId) ??
         ChargingStationUtils.getChargingStationId(this.index, this.getTemplateFromFile()) ??
         ''
@@ -169,7 +174,7 @@ export default class ChargingStation {
   };
 
   public hasAuthorizedTags(): boolean {
-    return !Utils.isEmptyArray(
+    return Utils.isNotEmptyArray(
       this.authorizedTagsCache.getAuthorizedTags(
         ChargingStationUtils.getAuthorizationFile(this.stationInfo)
       )
@@ -513,7 +518,7 @@ export default class ChargingStation {
           this.logPrefix(),
           undefined,
           (event, filename): void => {
-            if (!Utils.isEmptyString(filename) && event === 'change') {
+            if (Utils.isNotEmptyString(filename) && event === 'change') {
               try {
                 logger.debug(
                   `${this.logPrefix()} ${FileType.ChargingStationTemplate} ${
@@ -712,7 +717,7 @@ export default class ChargingStation {
         this.getAutomaticTransactionGeneratorConfigurationFromTemplate(),
       this
     );
-    if (!Utils.isEmptyArray(connectorIds)) {
+    if (Utils.isNotEmptyArray(connectorIds)) {
       for (const connectorId of connectorIds) {
         this.automaticTransactionGenerator?.startConnector(connectorId);
       }
@@ -723,7 +728,7 @@ export default class ChargingStation {
   }
 
   public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
-    if (!Utils.isEmptyArray(connectorIds)) {
+    if (Utils.isNotEmptyArray(connectorIds)) {
       for (const connectorId of connectorIds) {
         this.automaticTransactionGenerator?.stopConnector(connectorId);
       }
@@ -798,7 +803,7 @@ export default class ChargingStation {
   }
 
   private getSupervisionUrlOcppKey(): string {
-    return this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl;
+    return this.stationInfo.supervisionUrlOcppKey ?? VendorParametersKey.ConnectionUrl;
   }
 
   private getTemplateFromFile(): ChargingStationTemplate | undefined {
@@ -864,7 +869,7 @@ export default class ChargingStation {
     );
     stationInfo.ocppVersion = stationTemplate?.ocppVersion ?? OCPPVersion.VERSION_16;
     ChargingStationUtils.createSerialNumber(stationTemplate, stationInfo);
-    if (!Utils.isEmptyArray(stationTemplate?.power)) {
+    if (Utils.isNotEmptyArray(stationTemplate?.power)) {
       stationTemplate.power = stationTemplate.power as number[];
       const powerArrayRandomIndex = Math.floor(Utils.secureRandom() * stationTemplate.power.length);
       stationInfo.maximumPower =
@@ -881,7 +886,7 @@ export default class ChargingStation {
     stationInfo.firmwareVersionPattern =
       stationTemplate?.firmwareVersionPattern ?? Constants.SEMVER_PATTERN;
     if (
-      !Utils.isEmptyString(stationInfo.firmwareVersion) &&
+      Utils.isNotEmptyString(stationInfo.firmwareVersion) &&
       new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion) === false
     ) {
       logger.warn(
@@ -890,8 +895,11 @@ export default class ChargingStation {
         } does not match firmware version pattern '${stationInfo.firmwareVersionPattern}'`
       );
     }
-    stationInfo.firmwareUpgrade = merge(
+    stationInfo.firmwareUpgrade = merge<FirmwareUpgrade>(
       {
+        versionUpgrade: {
+          step: 1,
+        },
         reset: true,
       },
       stationTemplate?.firmwareUpgrade ?? {}
@@ -1033,10 +1041,9 @@ export default class ChargingStation {
     }
     if (
       this.stationInfo.firmwareStatus === FirmwareStatus.Installing &&
-      !Utils.isEmptyString(this.stationInfo.firmwareVersion) &&
-      !Utils.isEmptyString(this.stationInfo.firmwareVersionPattern)
+      Utils.isNotEmptyString(this.stationInfo.firmwareVersion) &&
+      Utils.isNotEmptyString(this.stationInfo.firmwareVersionPattern)
     ) {
-      const versionStep = this.stationInfo.firmwareUpgrade?.versionUpgrade?.step ?? 1;
       const patternGroup: number | undefined =
         this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
         this.stationInfo.firmwareVersion?.split('.').length;
@@ -1045,7 +1052,8 @@ export default class ChargingStation {
         ?.slice(1, patternGroup + 1);
       const patchLevelIndex = match.length - 1;
       match[patchLevelIndex] = (
-        Utils.convertToInt(match[patchLevelIndex]) + versionStep
+        Utils.convertToInt(match[patchLevelIndex]) +
+        this.stationInfo.firmwareUpgrade?.versionUpgrade?.step
       ).toString();
       this.stationInfo.firmwareVersion = match?.join('.');
     }
@@ -1098,7 +1106,7 @@ export default class ChargingStation {
       );
     }
     if (
-      !Utils.isEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
+      Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
       !ChargingStationConfigurationUtils.getConfigurationKey(
         this,
         this.stationInfo.amperageLimitationOcppKey
@@ -1354,7 +1362,7 @@ export default class ChargingStation {
           fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
         }
         const configurationData: ChargingStationConfiguration =
-          this.getConfigurationFromFile() ?? {};
+          Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
         this.ocppConfiguration?.configurationKey &&
           (configurationData.configurationKey = this.ocppConfiguration.configurationKey);
         this.stationInfo && (configurationData.stationInfo = this.stationInfo);
@@ -1406,7 +1414,10 @@ export default class ChargingStation {
       const configurationFromFile = this.getConfigurationFromFile();
       configuration = configurationFromFile?.configurationKey && configurationFromFile;
     }
-    configuration && delete configuration.stationInfo;
+    if (!Utils.isNullOrUndefined(configuration)) {
+      delete configuration.stationInfo;
+      delete configuration.configurationHash;
+    }
     return configuration;
   }
 
@@ -1763,7 +1774,7 @@ export default class ChargingStation {
 
   private getAmperageLimitation(): number | undefined {
     if (
-      !Utils.isEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
+      Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
       ChargingStationConfigurationUtils.getConfigurationKey(
         this,
         this.stationInfo.amperageLimitationOcppKey
@@ -1924,7 +1935,7 @@ export default class ChargingStation {
 
   private getConfiguredSupervisionUrl(): URL {
     const supervisionUrls = this.stationInfo?.supervisionUrls ?? Configuration.getSupervisionUrls();
-    if (!Utils.isEmptyArray(supervisionUrls)) {
+    if (Utils.isNotEmptyArray(supervisionUrls)) {
       switch (Configuration.getSupervisionUrlDistribution()) {
         case SupervisionUrlDistribution.ROUND_ROBIN:
           // FIXME