build(ci): fix linter errors
[e-mobility-charging-stations-simulator.git] / src / charging-station / Helpers.ts
index 0384da3e3026f0f0ce6b006f2b2a640183a7d8a9..15bd2c1f48cfb86438636f3f245c1d36912cca7c 100644 (file)
@@ -1,10 +1,12 @@
 import { createHash, randomBytes } from 'node:crypto';
 import type { EventEmitter } from 'node:events';
 import { basename, dirname, join } from 'node:path';
+import { env } from 'node:process';
 import { fileURLToPath } from 'node:url';
 
 import chalk from 'chalk';
 import {
+  type Interval,
   addDays,
   addSeconds,
   addWeeks,
@@ -32,6 +34,7 @@ import {
   ChargingProfileKindType,
   ChargingRateUnitType,
   type ChargingSchedulePeriod,
+  type ChargingStationConfiguration,
   type ChargingStationInfo,
   type ChargingStationTemplate,
   ChargingStationWorkerMessageEvents,
@@ -73,10 +76,13 @@ const moduleName = 'Helpers';
 
 export const getChargingStationId = (
   index: number,
-  stationTemplate: ChargingStationTemplate,
+  stationTemplate: ChargingStationTemplate | undefined,
 ): string => {
+  if (stationTemplate === undefined) {
+    return "Unknown 'chargingStationId'";
+  }
   // In case of multiple instances: add instance index to charging station id
-  const instanceIndex = process.env.CF_INSTANCE_INDEX ?? 0;
+  const instanceIndex = env.CF_INSTANCE_INDEX ?? 0;
   const idSuffix = stationTemplate?.nameSuffix ?? '';
   const idStr = `000000000${index.toString()}`;
   return stationTemplate?.fixedName
@@ -174,9 +180,9 @@ export const getPhaseRotationValue = (
   } else if (connectorId > 0 && numberOfPhases === 0) {
     return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
     // AC
-  } else if (connectorId > 0 && numberOfPhases === 1) {
+  } else if (connectorId >= 0 && numberOfPhases === 1) {
     return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
-  } else if (connectorId > 0 && numberOfPhases === 3) {
+  } else if (connectorId >= 0 && numberOfPhases === 3) {
     return `${connectorId}.${ConnectorPhaseRotation.RST}`;
   }
 };
@@ -249,6 +255,23 @@ export const checkTemplate = (
   }
 };
 
+export const checkConfiguration = (
+  stationConfiguration: ChargingStationConfiguration | undefined,
+  logPrefix: string,
+  configurationFile: string,
+): void => {
+  if (isNullOrUndefined(stationConfiguration)) {
+    const errorMsg = `Failed to read charging station configuration file ${configurationFile}`;
+    logger.error(`${logPrefix} ${errorMsg}`);
+    throw new BaseError(errorMsg);
+  }
+  if (isEmptyObject(stationConfiguration!)) {
+    const errorMsg = `Empty charging station configuration from file ${configurationFile}`;
+    logger.error(`${logPrefix} ${errorMsg}`);
+    throw new BaseError(errorMsg);
+  }
+};
+
 export const checkConnectorsConfiguration = (
   stationTemplate: ChargingStationTemplate,
   logPrefix: string,
@@ -262,7 +285,7 @@ export const checkConnectorsConfiguration = (
   checkConfiguredMaxConnectors(configuredMaxConnectors, logPrefix, templateFile);
   const templateMaxConnectors = getMaxNumberOfConnectors(stationTemplate.Connectors!);
   checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile);
-  const templateMaxAvailableConnectors = stationTemplate.Connectors![0]
+  const templateMaxAvailableConnectors = stationTemplate.Connectors?.[0]
     ? templateMaxConnectors - 1
     : templateMaxConnectors;
   if (
@@ -339,11 +362,12 @@ export const initializeConnectorsMapStatus = (
 };
 
 export const resetConnectorStatus = (connectorStatus: ConnectorStatus): void => {
-  connectorStatus.chargingProfiles = isNotEmptyArray(connectorStatus.chargingProfiles)
-    ? connectorStatus.chargingProfiles?.filter(
-        (chargingProfile) => chargingProfile.transactionId !== connectorStatus?.transactionId,
-      )
-    : [];
+  connectorStatus.chargingProfiles =
+    connectorStatus.transactionId && isNotEmptyArray(connectorStatus.chargingProfiles)
+      ? connectorStatus.chargingProfiles?.filter(
+          (chargingProfile) => chargingProfile.transactionId !== connectorStatus.transactionId,
+        )
+      : [];
   connectorStatus.idTagLocalAuthorized = false;
   connectorStatus.idTagAuthorized = false;
   connectorStatus.transactionRemoteStarted = false;
@@ -361,7 +385,7 @@ export const createBootNotificationRequest = (
   stationInfo: ChargingStationInfo,
   bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp,
 ): BootNotificationRequest => {
-  const ocppVersion = stationInfo.ocppVersion ?? OCPPVersion.VERSION_16;
+  const ocppVersion = stationInfo.ocppVersion!;
   switch (ocppVersion) {
     case OCPPVersion.VERSION_16:
       return {
@@ -451,12 +475,9 @@ export const stationTemplateToStationInfo = (
 export const createSerialNumber = (
   stationTemplate: ChargingStationTemplate,
   stationInfo: ChargingStationInfo,
-  params: {
+  params?: {
     randomSerialNumberUpperCase?: boolean;
     randomSerialNumber?: boolean;
-  } = {
-    randomSerialNumberUpperCase: true,
-    randomSerialNumber: true,
   },
 ): void => {
   params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params };
@@ -560,14 +581,14 @@ export const getChargingStationConnectorChargingProfilesPowerLimit = (
     if (!isNullOrUndefined(result)) {
       limit = result?.limit;
       chargingProfile = result?.chargingProfile;
-      switch (chargingStation.getCurrentOutType()) {
+      switch (chargingStation.stationInfo?.currentOutType) {
         case CurrentType.AC:
           limit =
             chargingProfile?.chargingSchedule?.chargingRateUnit === ChargingRateUnitType.WATT
               ? limit
               : ACElectricUtils.powerTotal(
                   chargingStation.getNumberOfPhases(),
-                  chargingStation.getVoltageOut(),
+                  chargingStation.stationInfo.voltageOut!,
                   limit!,
                 );
           break;
@@ -575,10 +596,10 @@ export const getChargingStationConnectorChargingProfilesPowerLimit = (
           limit =
             chargingProfile?.chargingSchedule?.chargingRateUnit === ChargingRateUnitType.WATT
               ? limit
-              : DCElectricUtils.power(chargingStation.getVoltageOut(), limit!);
+              : DCElectricUtils.power(chargingStation.stationInfo.voltageOut!, limit!);
       }
       const connectorMaximumPower =
-        chargingStation.getMaximumPower() / chargingStation.powerDivider;
+        chargingStation.stationInfo.maximumPower! / chargingStation.powerDivider;
       if (limit! > connectorMaximumPower) {
         logger.error(
           `${chargingStation.logPrefix()} ${moduleName}.getChargingStationConnectorChargingProfilesPowerLimit: Charging profile id ${chargingProfile?.chargingProfileId} limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`,
@@ -647,7 +668,7 @@ const getConfiguredMaxNumberOfConnectors = (stationTemplate: ChargingStationTemp
   } else if (isUndefined(stationTemplate.numberOfConnectors) === false) {
     configuredMaxNumberOfConnectors = stationTemplate.numberOfConnectors as number;
   } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
-    configuredMaxNumberOfConnectors = stationTemplate.Connectors[0]
+    configuredMaxNumberOfConnectors = stationTemplate.Connectors?.[0]
       ? getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
       : getMaxNumberOfConnectors(stationTemplate.Connectors);
   } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
@@ -711,12 +732,12 @@ const warnDeprecatedTemplateKey = (
   templateFile: string,
   logMsgToAppend = '',
 ): void => {
-  if (!isUndefined(template[key as keyof ChargingStationTemplate])) {
+  if (!isUndefined(template?.[key as keyof ChargingStationTemplate])) {
     const logMsg = `Deprecated template key '${key}' usage in file '${templateFile}'${
       isNotEmptyString(logMsgToAppend) ? `. ${logMsgToAppend}` : ''
     }`;
     logger.warn(`${logPrefix} ${logMsg}`);
-    console.warn(chalk.yellow(`${logMsg}`));
+    console.warn(`${chalk.green(logPrefix)} ${chalk.yellow(logMsg)}`);
   }
 };
 
@@ -725,7 +746,7 @@ const convertDeprecatedTemplateKey = (
   deprecatedKey: string,
   key?: string,
 ): void => {
-  if (!isUndefined(template[deprecatedKey as keyof ChargingStationTemplate])) {
+  if (!isUndefined(template?.[deprecatedKey as keyof ChargingStationTemplate])) {
     if (!isUndefined(key)) {
       (template as unknown as Record<string, unknown>)[key!] =
         template[deprecatedKey as keyof ChargingStationTemplate];
@@ -966,7 +987,10 @@ const canProceedRecurringChargingProfile = (
     );
     return false;
   }
-  if (isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule)) {
+  if (
+    chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING &&
+    isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule)
+  ) {
     logger.error(
       `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined`,
     );