refactor: cleanup connectors initialization code
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 27 Apr 2023 16:55:02 +0000 (18:55 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 27 Apr 2023 16:55:02 +0000 (18:55 +0200)
Reference: https://github.com/SAP/e-mobility-charging-stations-simulator/issues/349

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationUtils.ts
src/types/index.ts

index 716ad017e689f76e7a077931ea36356235c7d1e3..b3d4bdd98016cbf5d35288c15bff552417859497 100644 (file)
@@ -913,47 +913,8 @@ export class ChargingStation {
     stationInfo.resetTime = !Utils.isNullOrUndefined(stationTemplate?.resetTime)
       ? stationTemplate.resetTime * 1000
       : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
-    const configuredMaxConnectors =
-      ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate);
-    ChargingStationUtils.checkConfiguredMaxConnectors(
-      configuredMaxConnectors,
-      this.templateFile,
-      this.logPrefix()
-    );
-    // Build evses or connectors if needed (FIXME: should be factored out)
-    if (stationInfo?.Connectors && !stationInfo?.Evses) {
-      const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
-        stationTemplate.Connectors
-      );
-      ChargingStationUtils.checkTemplateMaxConnectors(
-        templateMaxConnectors,
-        this.templateFile,
-        this.logPrefix()
-      );
-      if (
-        configuredMaxConnectors >
-          (stationTemplate?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) &&
-        !stationTemplate?.randomConnectors
-      ) {
-        logger.warn(
-          `${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${
-            this.templateFile
-          }, forcing random connector configurations affectation`
-        );
-        stationInfo.randomConnectors = true;
-      }
-      this.initializeConnectors(stationInfo, configuredMaxConnectors);
-    } else if (stationInfo?.Evses && !stationInfo?.Connectors) {
-      this.initializeEvses(stationInfo);
-    } else if (stationInfo?.Evses && stationInfo?.Connectors) {
-      const errorMsg = `Connectors and evses defined at the same time in template file ${this.templateFile}`;
-      logger.error(`${this.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    } else {
-      const errorMsg = `No connectors or evses defined in template file ${this.templateFile}`;
-      logger.error(`${this.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    }
+    // Initialize evses or connectors if needed (FIXME: should be factored out)
+    this.initializeConnectorsOrEvses(stationInfo);
     stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
     ChargingStationUtils.createStationInfoHash(stationInfo);
     return stationInfo;
@@ -1034,8 +995,9 @@ export class ChargingStation {
       this.stationInfo.firmwareVersion = match?.join('.');
     }
     this.saveStationInfo();
-    // Avoid duplication of connectors related information in RAM
+    // Avoid duplication of connectors or evses related information in RAM
     delete this.stationInfo?.Connectors;
+    delete this.stationInfo?.Evses;
     this.configuredSupervisionUrl = this.getConfiguredSupervisionUrl();
     if (this.getEnableStatistics() === true) {
       this.performanceStatistics = PerformanceStatistics.getInstance(
@@ -1249,10 +1211,23 @@ export class ChargingStation {
     this.saveOcppConfiguration();
   }
 
-  private initializeConnectors(
-    stationInfo: ChargingStationInfo,
-    configuredMaxConnectors: number
-  ): void {
+  private initializeConnectorsOrEvses(stationInfo: ChargingStationInfo) {
+    if (stationInfo?.Connectors && !stationInfo?.Evses) {
+      this.initializeConnectors(stationInfo);
+    } else if (stationInfo?.Evses && !stationInfo?.Connectors) {
+      this.initializeEvses(stationInfo);
+    } else if (stationInfo?.Evses && stationInfo?.Connectors) {
+      const errorMsg = `Connectors and evses defined at the same time in template file ${this.templateFile}`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    } else {
+      const errorMsg = `No connectors or evses defined in template file ${this.templateFile}`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+  }
+
+  private initializeConnectors(stationInfo: ChargingStationInfo): void {
     if (!stationInfo?.Connectors && this.connectors.size === 0) {
       const logMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`;
       logger.error(`${this.logPrefix()} ${logMsg}`);
@@ -1266,6 +1241,13 @@ export class ChargingStation {
       );
     }
     if (stationInfo?.Connectors) {
+      const configuredMaxConnectors =
+        ChargingStationUtils.getConfiguredNumberOfConnectors(stationInfo);
+      ChargingStationUtils.checkConfiguredMaxConnectors(
+        configuredMaxConnectors,
+        this.templateFile,
+        this.logPrefix()
+      );
       const connectorsConfigHash = crypto
         .createHash(Constants.DEFAULT_HASH_ALGORITHM)
         .update(`${JSON.stringify(stationInfo?.Connectors)}${configuredMaxConnectors.toString()}`)
@@ -1275,54 +1257,70 @@ export class ChargingStation {
       if (this.connectors?.size === 0 || connectorsConfigChanged) {
         connectorsConfigChanged && this.connectors.clear();
         this.connectorsConfigurationHash = connectorsConfigHash;
+        const connectorZeroStatus = stationInfo?.Connectors[0];
         // Add connector id 0
-        let lastConnector = '0';
-        for (lastConnector in stationInfo?.Connectors) {
-          const connectorStatus = stationInfo?.Connectors[lastConnector];
-          const lastConnectorId = Utils.convertToInt(lastConnector);
-          if (
-            lastConnectorId === 0 &&
-            this.getUseConnectorId0(stationInfo) === true &&
-            connectorStatus
-          ) {
-            ChargingStationUtils.checkStationInfoConnectorStatus(
-              lastConnectorId,
-              connectorStatus,
-              this.logPrefix(),
-              this.templateFile
-            );
-            this.connectors.set(
-              lastConnectorId,
-              Utils.cloneObject<ConnectorStatus>(connectorStatus)
-            );
-            this.getConnectorStatus(lastConnectorId).availability = AvailabilityType.Operative;
-            if (Utils.isUndefined(this.getConnectorStatus(lastConnectorId)?.chargingProfiles)) {
-              this.getConnectorStatus(lastConnectorId).chargingProfiles = [];
-            }
+        if (connectorZeroStatus && this.getUseConnectorId0(stationInfo) === true) {
+          ChargingStationUtils.checkStationInfoConnectorStatus(
+            0,
+            connectorZeroStatus,
+            this.logPrefix(),
+            this.templateFile
+          );
+          this.connectors.set(0, Utils.cloneObject<ConnectorStatus>(connectorZeroStatus));
+          this.getConnectorStatus(0).availability = AvailabilityType.Operative;
+          if (Utils.isUndefined(this.getConnectorStatus(0)?.chargingProfiles)) {
+            this.getConnectorStatus(0).chargingProfiles = [];
           }
         }
-        // Generate all connectors
+        // Add remaining connectors
         const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
-          stationInfo?.Connectors
+          stationInfo.Connectors
         );
-        if ((stationInfo?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) > 0) {
-          for (let index = 1; index <= configuredMaxConnectors; index++) {
-            const randConnectorId = stationInfo?.randomConnectors
-              ? Utils.getRandomInteger(Utils.convertToInt(lastConnector), 1)
-              : index;
-            const connectorStatus = stationInfo?.Connectors[randConnectorId.toString()];
+        ChargingStationUtils.checkTemplateMaxConnectors(
+          templateMaxConnectors,
+          this.templateFile,
+          this.logPrefix()
+        );
+        if (
+          configuredMaxConnectors >
+            (stationInfo?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) &&
+          !stationInfo?.randomConnectors
+        ) {
+          logger.warn(
+            `${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${
+              this.templateFile
+            }, forcing random connector configurations affectation`
+          );
+          stationInfo.randomConnectors = true;
+        }
+        const templateMaxAvailableConnectors = stationInfo?.Connectors[0]
+          ? templateMaxConnectors - 1
+          : templateMaxConnectors;
+        if (templateMaxAvailableConnectors > 0) {
+          for (let connectorId = 1; connectorId <= configuredMaxConnectors; connectorId++) {
+            const templateConnectorId = stationInfo?.randomConnectors
+              ? Utils.getRandomInteger(templateMaxAvailableConnectors, 1)
+              : connectorId;
+            const connectorStatus = stationInfo?.Connectors[templateConnectorId];
             ChargingStationUtils.checkStationInfoConnectorStatus(
-              randConnectorId,
+              templateConnectorId,
               connectorStatus,
               this.logPrefix(),
               this.templateFile
             );
-            this.connectors.set(index, Utils.cloneObject<ConnectorStatus>(connectorStatus));
-            this.getConnectorStatus(index).availability = AvailabilityType.Operative;
-            if (Utils.isUndefined(this.getConnectorStatus(index)?.chargingProfiles)) {
-              this.getConnectorStatus(index).chargingProfiles = [];
+            this.connectors.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+            this.getConnectorStatus(connectorId).availability = AvailabilityType.Operative;
+            if (Utils.isUndefined(this.getConnectorStatus(connectorId)?.chargingProfiles)) {
+              this.getConnectorStatus(connectorId).chargingProfiles = [];
             }
+            ChargingStationUtils.initializeConnectorsMapStatus(this.connectors, this.logPrefix());
           }
+        } else {
+          logger.warn(
+            `${this.logPrefix()} Charging station information from template ${
+              this.templateFile
+            } with no connectors configuration defined, cannot create connectors`
+          );
         }
       }
     } else {
@@ -1332,29 +1330,13 @@ export class ChargingStation {
         } with no connectors configuration defined, using already defined connectors`
       );
     }
-    // Initialize connectors status
-    for (const connectorId of this.connectors.keys()) {
-      if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
-        logger.warn(
-          `${this.logPrefix()} Connector ${connectorId} at initialization has a transaction started: ${
-            this.getConnectorStatus(connectorId)?.transactionId
-          }`
-        );
-      }
-      if (
-        connectorId > 0 &&
-        Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionStarted)
-      ) {
-        ChargingStationUtils.initializeConnectorStatus(this.getConnectorStatus(connectorId));
-      }
-    }
   }
 
   private initializeEvses(stationInfo: ChargingStationInfo): void {
     if (!stationInfo?.Evses && this.evses.size === 0) {
       const logMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
-      logger.warn(`${this.logPrefix()} ${logMsg}`);
-      return;
+      logger.error(`${this.logPrefix()} ${logMsg}`);
+      throw new BaseError(logMsg);
     }
     if (!stationInfo?.Evses[0]) {
       logger.warn(
@@ -1373,27 +1355,36 @@ export class ChargingStation {
       if (this.evses?.size === 0 || evsesConfigChanged) {
         evsesConfigChanged && this.evses.clear();
         this.evsesConfigurationHash = evsesConfigHash;
-        for (const evse in stationInfo?.Evses) {
-          this.evses.set(Utils.convertToInt(evse), {
-            connectors: ChargingStationUtils.buildConnectorsMap(
-              stationInfo?.Evses[evse]?.Connectors,
-              this.logPrefix(),
+        const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationInfo?.Evses);
+        if (templateMaxEvses > 0) {
+          for (const evse in stationInfo.Evses) {
+            this.evses.set(Utils.convertToInt(evse), {
+              connectors: ChargingStationUtils.buildConnectorsMap(
+                stationInfo?.Evses[evse]?.Connectors,
+                this.logPrefix(),
+                this.templateFile
+              ),
+              availability: AvailabilityType.Operative,
+            });
+            ChargingStationUtils.initializeConnectorsMapStatus(
+              this.evses.get(Utils.convertToInt(evse))?.connectors,
+              this.logPrefix()
+            );
+          }
+        } else {
+          logger.warn(
+            `${this.logPrefix()} Charging station information from template ${
               this.templateFile
-            ),
-            availability: AvailabilityType.Operative,
-          });
-          ChargingStationUtils.initializeConnectorsMapStatus(
-            this.evses.get(Utils.convertToInt(evse))?.connectors,
-            this.logPrefix()
+            } with no evses configuration defined, cannot create evses`
           );
         }
+      } else {
+        logger.warn(
+          `${this.logPrefix()} Charging station information from template ${
+            this.templateFile
+          } with no evses configuration defined, using already defined evses`
+        );
       }
-    } else {
-      logger.warn(
-        `${this.logPrefix()} Charging station information from template ${
-          this.templateFile
-        } with no evses configuration defined, using already defined evses`
-      );
     }
   }
 
index f61dd46361613d4db2b6a731dc23fd5cb14553be..c5c42f02944a451c2b8469c0d325361ed6a77376 100644 (file)
@@ -20,6 +20,7 @@ import {
   type ChargingStationTemplate,
   type ConnectorStatus,
   CurrentType,
+  type EvseTemplate,
   type OCPP16BootNotificationRequest,
   type OCPP20BootNotificationRequest,
   OCPPVersion,
@@ -94,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;
@@ -117,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
         );
       }
     }
@@ -175,20 +183,26 @@ export class ChargingStationUtils {
     templateFile: string
   ): Map<number, ConnectorStatus> {
     const connectorsMap = new Map<number, ConnectorStatus>();
-    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));
-      connectorsMap.get(connectorId).availability = AvailabilityType.Operative;
-      if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) {
-        connectorsMap.get(connectorId).chargingProfiles = [];
+    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));
+        connectorsMap.get(connectorId).availability = AvailabilityType.Operative;
+        if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) {
+          connectorsMap.get(connectorId).chargingProfiles = [];
+        }
       }
+    } else {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map`
+      );
     }
     return connectorsMap;
   }
index bdbe0422b039a83d753f37f5e656b624da9b10cf..1a349c3a6ddf521287602488b71610d4878e8196 100644 (file)
@@ -60,6 +60,7 @@ export {
   type ErrorResponse,
   ErrorType,
   type EvseStatus,
+  type EvseTemplate,
   FileType,
   FirmwareStatus,
   type FirmwareStatusNotificationRequest,