fix: fix number of available evses calculation
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationUtils.ts
index e2e9821e28c915804c7a9aec4bac79468023e956..49a61101533043ae15cb09c6783eb197bf452cfd 100644 (file)
@@ -9,6 +9,7 @@ import type { ChargingStation } from './internal';
 import { BaseError } from '../exception';
 import {
   AmpereUnits,
+  AvailabilityType,
   type BootNotificationRequest,
   BootReasonEnumType,
   type ChargingProfile,
@@ -19,6 +20,7 @@ import {
   type ChargingStationTemplate,
   type ConnectorStatus,
   CurrentType,
+  type EvseTemplate,
   type OCPP16BootNotificationRequest,
   type OCPP20BootNotificationRequest,
   OCPPVersion,
@@ -93,6 +95,13 @@ export class ChargingStationUtils {
     return true;
   }
 
+  public static getMaxNumberOfEvses(evses: Record<string, EvseTemplate>): number {
+    if (!evses) {
+      return -1;
+    }
+    return Object.keys(evses).length;
+  }
+
   public static getMaxNumberOfConnectors(connectors: Record<string, ConnectorStatus>): number {
     if (!connectors) {
       return -1;
@@ -116,26 +125,26 @@ export class ChargingStationUtils {
     }
   }
 
-  public static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
+  public static getConfiguredNumberOfConnectors(stationInfo: ChargingStationInfo): number {
     let configuredMaxConnectors: number;
-    if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
-      const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
+    if (Utils.isNotEmptyArray(stationInfo.numberOfConnectors) === true) {
+      const numberOfConnectors = stationInfo.numberOfConnectors as number[];
       configuredMaxConnectors =
         numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
-    } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) {
-      configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
-    } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
-      configuredMaxConnectors = stationTemplate?.Connectors[0]
-        ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
-        : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors);
-    } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
+    } else if (Utils.isUndefined(stationInfo.numberOfConnectors) === false) {
+      configuredMaxConnectors = stationInfo.numberOfConnectors as number;
+    } else if (stationInfo.Connectors && !stationInfo.Evses) {
+      configuredMaxConnectors = stationInfo?.Connectors[0]
+        ? ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors) - 1
+        : ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors);
+    } else if (stationInfo.Evses && !stationInfo.Connectors) {
       configuredMaxConnectors = 0;
-      for (const evse in stationTemplate.Evses) {
+      for (const evse in stationInfo.Evses) {
         if (evse === '0') {
           continue;
         }
         configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
-          stationTemplate.Evses[evse].Connectors
+          stationInfo.Evses[evse].Connectors
         );
       }
     }
@@ -154,6 +163,85 @@ export class ChargingStationUtils {
     }
   }
 
+  public static checkStationInfoConnectorStatus(
+    connectorId: number,
+    connectorStatus: ConnectorStatus,
+    logPrefix: string,
+    templateFile: string
+  ): void {
+    if (!Utils.isNullOrUndefined(connectorStatus?.status)) {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId} status configuration defined, undefine it`
+      );
+      delete connectorStatus.status;
+    }
+  }
+
+  public static buildConnectorsMap(
+    connectors: Record<string, ConnectorStatus>,
+    logPrefix: string,
+    templateFile: string
+  ): Map<number, ConnectorStatus> {
+    const connectorsMap = new Map<number, ConnectorStatus>();
+    if (ChargingStationUtils.getMaxNumberOfConnectors(connectors) > 0) {
+      for (const connector in connectors) {
+        const connectorStatus = connectors[connector];
+        const connectorId = Utils.convertToInt(connector);
+        ChargingStationUtils.checkStationInfoConnectorStatus(
+          connectorId,
+          connectorStatus,
+          logPrefix,
+          templateFile
+        );
+        connectorsMap.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+      }
+    } else {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map`
+      );
+    }
+    return connectorsMap;
+  }
+
+  public static initializeConnectorsMapStatus(
+    connectors: Map<number, ConnectorStatus>,
+    logPrefix: string
+  ): void {
+    for (const connectorId of connectors.keys()) {
+      if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) {
+        logger.warn(
+          `${logPrefix} Connector id ${connectorId} at initialization has a transaction started with id ${
+            connectors.get(connectorId)?.transactionId
+          }`
+        );
+      }
+      if (connectorId === 0) {
+        connectors.get(connectorId).availability = AvailabilityType.Operative;
+        if (Utils.isUndefined(connectors.get(connectorId)?.chargingProfiles)) {
+          connectors.get(connectorId).chargingProfiles = [];
+        }
+      } else if (
+        connectorId > 0 &&
+        Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted)
+      ) {
+        ChargingStationUtils.initializeConnectorStatus(connectors.get(connectorId));
+      }
+    }
+  }
+
+  public static resetConnectorStatus(connectorStatus: ConnectorStatus): void {
+    connectorStatus.idTagLocalAuthorized = false;
+    connectorStatus.idTagAuthorized = false;
+    connectorStatus.transactionRemoteStarted = false;
+    connectorStatus.transactionStarted = false;
+    delete connectorStatus?.localAuthorizeIdTag;
+    delete connectorStatus?.authorizeIdTag;
+    delete connectorStatus?.transactionId;
+    delete connectorStatus?.transactionIdTag;
+    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
+    delete connectorStatus?.transactionBeginMeterValue;
+  }
+
   public static createBootNotificationRequest(
     stationInfo: ChargingStationInfo,
     bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp
@@ -427,6 +515,19 @@ export class ChargingStationUtils {
     );
   }
 
+  private static initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
+    connectorStatus.availability = AvailabilityType.Operative;
+    connectorStatus.idTagLocalAuthorized = false;
+    connectorStatus.idTagAuthorized = false;
+    connectorStatus.transactionRemoteStarted = false;
+    connectorStatus.transactionStarted = false;
+    connectorStatus.energyActiveImportRegisterValue = 0;
+    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
+    if (Utils.isUndefined(connectorStatus.chargingProfiles)) {
+      connectorStatus.chargingProfiles = [];
+    }
+  }
+
   private static warnDeprecatedTemplateKey(
     template: ChargingStationTemplate,
     key: string,
@@ -455,7 +556,7 @@ export class ChargingStationUtils {
   }
 
   /**
-   * Charging profiles should already be sorted by connectorId and stack level (highest stack level has priority)
+   * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority)
    *
    * @param chargingProfiles -
    * @param logPrefix -