Merge pull request #596 from JulianHBuecher/reservation-process-bug-fix
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationUtils.ts
index 517a3c9a5e0f40c4e56d9f7ea84cafaf13279793..033fc4b36f79647746106169fe462834d241e463 100644 (file)
@@ -1,11 +1,12 @@
 import crypto from 'node:crypto';
+import type EventEmitter from 'node:events';
 import path from 'node:path';
 import { fileURLToPath } from 'node:url';
 
 import chalk from 'chalk';
 import moment from 'moment';
 
-import type { ChargingStation } from './internal';
+import type { ChargingStation } from './ChargingStation';
 import { BaseError } from '../exception';
 import {
   AmpereUnits,
@@ -18,6 +19,7 @@ import {
   type ChargingSchedulePeriod,
   type ChargingStationInfo,
   type ChargingStationTemplate,
+  ChargingStationWorkerMessageEvents,
   ConnectorPhaseRotation,
   type ConnectorStatus,
   ConnectorStatusEnum,
@@ -29,15 +31,7 @@ import {
   RecurrencyKindType,
   Voltage,
 } from '../types';
-import {
-  ACElectricUtils,
-  Configuration,
-  Constants,
-  DCElectricUtils,
-  Utils,
-  logger,
-} from '../utils';
-import { WorkerProcessType } from '../worker';
+import { ACElectricUtils, Constants, DCElectricUtils, Utils, logger } from '../utils';
 
 const moduleName = 'ChargingStationUtils';
 
@@ -153,10 +147,42 @@ export class ChargingStationUtils {
     return connectorBootStatus;
   }
 
+  public static checkTemplate(
+    stationTemplate: ChargingStationTemplate,
+    logPrefix: string,
+    templateFile: string
+  ) {
+    if (Utils.isNullOrUndefined(stationTemplate)) {
+      const errorMsg = `Failed to read charging station template file ${templateFile}`;
+      logger.error(`${logPrefix} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+    if (Utils.isEmptyObject(stationTemplate)) {
+      const errorMsg = `Empty charging station information from template file ${templateFile}`;
+      logger.error(`${logPrefix} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+    if (Utils.isEmptyObject(stationTemplate.AutomaticTransactionGenerator)) {
+      stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION;
+      logger.warn(
+        `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`,
+        Constants.DEFAULT_ATG_CONFIGURATION
+      );
+    }
+    if (
+      Utils.isNullOrUndefined(stationTemplate.idTagsFile) ||
+      Utils.isEmptyString(stationTemplate.idTagsFile)
+    ) {
+      logger.warn(
+        `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator`
+      );
+    }
+  }
+
   public static checkConnectorsConfiguration(
-    stationTemplate: ChargingStationTemplate | ChargingStationInfo,
-    templateFile: string,
-    logPrefix: string
+    stationTemplate: ChargingStationTemplate,
+    logPrefix: string,
+    templateFile: string
   ): {
     configuredMaxConnectors: number;
     templateMaxConnectors: number;
@@ -166,13 +192,13 @@ export class ChargingStationUtils {
       ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate);
     ChargingStationUtils.checkConfiguredMaxConnectors(
       configuredMaxConnectors,
-      templateFile,
-      logPrefix
+      logPrefix,
+      templateFile
     );
     const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
       stationTemplate.Connectors
     );
-    ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, templateFile, logPrefix);
+    ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile);
     const templateMaxAvailableConnectors = stationTemplate?.Connectors[0]
       ? templateMaxConnectors - 1
       : templateMaxConnectors;
@@ -319,20 +345,10 @@ export class ChargingStationUtils {
     }
   }
 
-  public static workerPoolInUse(): boolean {
-    return [WorkerProcessType.dynamicPool, WorkerProcessType.staticPool].includes(
-      Configuration.getWorker().processType
-    );
-  }
-
-  public static workerDynamicPoolInUse(): boolean {
-    return Configuration.getWorker().processType === WorkerProcessType.dynamicPool;
-  }
-
   public static warnTemplateKeysDeprecation(
-    templateFile: string,
     stationTemplate: ChargingStationTemplate,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ) {
     const templateKeys: { key: string; deprecatedKey: string }[] = [
       { key: 'supervisionUrls', deprecatedKey: 'supervisionUrl' },
@@ -342,8 +358,8 @@ export class ChargingStationUtils {
       ChargingStationUtils.warnDeprecatedTemplateKey(
         stationTemplate,
         templateKey.deprecatedKey,
-        templateFile,
         logPrefix,
+        templateFile,
         `Use '${templateKey.key}' instead`
       );
       ChargingStationUtils.convertDeprecatedTemplateKey(
@@ -357,9 +373,11 @@ export class ChargingStationUtils {
   public static stationTemplateToStationInfo(
     stationTemplate: ChargingStationTemplate
   ): ChargingStationInfo {
-    stationTemplate = Utils.cloneObject(stationTemplate);
+    stationTemplate = Utils.cloneObject<ChargingStationTemplate>(stationTemplate);
     delete stationTemplate.power;
     delete stationTemplate.powerUnit;
+    delete stationTemplate?.Connectors;
+    delete stationTemplate?.Evses;
     delete stationTemplate.Configuration;
     delete stationTemplate.AutomaticTransactionGenerator;
     delete stationTemplate.chargeBoxSerialNumberPrefix;
@@ -437,15 +455,15 @@ export class ChargingStationUtils {
     let limit: number, matchingChargingProfile: ChargingProfile;
     // Get charging profiles for connector and sort by stack level
     const chargingProfiles =
-      Utils.cloneObject(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)?.sort(
-        (a, b) => b.stackLevel - a.stackLevel
-      ) ?? [];
+      Utils.cloneObject<ChargingProfile[]>(
+        chargingStation.getConnectorStatus(connectorId)?.chargingProfiles
+      )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? [];
     // Get profiles on connector 0
     if (chargingStation.getConnectorStatus(0)?.chargingProfiles) {
       chargingProfiles.push(
-        ...Utils.cloneObject(chargingStation.getConnectorStatus(0).chargingProfiles).sort(
-          (a, b) => b.stackLevel - a.stackLevel
-        )
+        ...Utils.cloneObject<ChargingProfile[]>(
+          chargingStation.getConnectorStatus(0).chargingProfiles
+        ).sort((a, b) => b.stackLevel - a.stackLevel)
       );
     }
     if (Utils.isNotEmptyArray(chargingProfiles)) {
@@ -493,8 +511,8 @@ export class ChargingStationUtils {
 
   public static getDefaultVoltageOut(
     currentType: CurrentType,
-    templateFile: string,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ): Voltage {
     const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
     let defaultVoltageOut: number;
@@ -516,16 +534,33 @@ export class ChargingStationUtils {
     return (
       stationInfo.idTagsFile &&
       path.join(
-        path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
+        path.dirname(fileURLToPath(import.meta.url)),
         'assets',
         path.basename(stationInfo.idTagsFile)
       )
     );
   }
 
-  private static getConfiguredNumberOfConnectors(
-    stationTemplate: ChargingStationTemplate | ChargingStationInfo
-  ): number {
+  public static waitForChargingStationEvents = async (
+    emitter: EventEmitter,
+    event: ChargingStationWorkerMessageEvents,
+    eventsToWait: number
+  ): Promise<number> => {
+    return new Promise((resolve) => {
+      let events = 0;
+      if (eventsToWait === 0) {
+        resolve(events);
+      }
+      emitter.on(event, () => {
+        ++events;
+        if (events === eventsToWait) {
+          resolve(events);
+        }
+      });
+    });
+  };
+
+  private static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
     let configuredMaxConnectors: number;
     if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
       const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
@@ -553,8 +588,8 @@ export class ChargingStationUtils {
 
   private static checkConfiguredMaxConnectors(
     configuredMaxConnectors: number,
-    templateFile: string,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ): void {
     if (configuredMaxConnectors <= 0) {
       logger.warn(
@@ -565,8 +600,8 @@ export class ChargingStationUtils {
 
   private static checkTemplateMaxConnectors(
     templateMaxConnectors: number,
-    templateFile: string,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ): void {
     if (templateMaxConnectors === 0) {
       logger.warn(
@@ -595,8 +630,8 @@ export class ChargingStationUtils {
   private static warnDeprecatedTemplateKey(
     template: ChargingStationTemplate,
     key: string,
-    templateFile: string,
     logPrefix: string,
+    templateFile: string,
     logMsgToAppend = ''
   ): void {
     if (!Utils.isUndefined(template[key])) {