feat: make evse and connector configurations in template mutually
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 26 Apr 2023 20:35:43 +0000 (22:35 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 26 Apr 2023 20:35:43 +0000 (22:35 +0200)
exclusive

Evse configurations is still not use at that stage

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/ChargingStationTemplate.ts
src/types/Evse.ts [new file with mode: 0644]
src/types/EvseStatus.ts [deleted file]
src/types/internal.ts

index 46fae1811d4e0f7bdc7b435047bb60f9ff00c70a..96bf6c1b3370fc29a772fc5baa01d5ef172c5509 100644 (file)
@@ -929,28 +929,40 @@ export class ChargingStation {
       this.templateFile,
       this.logPrefix()
     );
-    const templateMaxConnectors =
-      ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate);
-    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`
+    // Build evses or connectors if needed (FIXME: should be factored out)
+    if (stationInfo?.Connectors && !stationInfo?.Evses) {
+      const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
+        stationTemplate.Connectors
       );
-      stationInfo.randomConnectors = true;
+      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);
     }
-    // Build connectors if needed (FIXME: should be factored out)
-    this.initializeConnectors(stationInfo, configuredMaxConnectors, templateMaxConnectors);
-    this.initializeEvses(stationInfo);
     stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
     ChargingStationUtils.createStationInfoHash(stationInfo);
     return stationInfo;
@@ -1248,8 +1260,7 @@ export class ChargingStation {
 
   private initializeConnectors(
     stationInfo: ChargingStationInfo,
-    configuredMaxConnectors: number,
-    templateMaxConnectors: number
+    configuredMaxConnectors: number
   ): 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`;
@@ -1295,6 +1306,9 @@ export class ChargingStation {
           }
         }
         // Generate all connectors
+        const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
+          stationInfo?.Connectors
+        );
         if ((stationInfo?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) > 0) {
           for (let index = 1; index <= configuredMaxConnectors; index++) {
             const randConnectorId = stationInfo?.randomConnectors
@@ -1317,7 +1331,7 @@ export class ChargingStation {
         } with no connectors configuration defined, using already defined connectors`
       );
     }
-    // Initialize transaction attributes on connectors
+    // Initialize connectors status
     for (const connectorId of this.connectors.keys()) {
       if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
         logger.warn(
@@ -1330,7 +1344,42 @@ export class ChargingStation {
         connectorId > 0 &&
         Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionStarted)
       ) {
-        this.initializeConnectorStatus(connectorId);
+        this.initializeConnectorStatus(this.getConnectorStatus(connectorId));
+      }
+    }
+  }
+
+  private buildConnectorsMap(
+    connectors: Record<string, ConnectorStatus>
+  ): Map<number, ConnectorStatus> {
+    const connectorsMap = new Map<number, ConnectorStatus>();
+    for (const connector in connectors) {
+      const connectorStatus = connectors[connector];
+      const connectorId = Utils.convertToInt(connector);
+      this.checkStationInfoConnectorStatus(connectorId, connectorStatus);
+      connectorsMap.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+      connectorsMap.get(connectorId).availability = AvailabilityType.Operative;
+      if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) {
+        connectorsMap.get(connectorId).chargingProfiles = [];
+      }
+    }
+    return connectorsMap;
+  }
+
+  private initializeConnectorsMapStatus(connectors: Map<number, ConnectorStatus>): void {
+    for (const connectorId of connectors.keys()) {
+      if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) {
+        logger.warn(
+          `${this.logPrefix()} Connector ${connectorId} at initialization has a transaction started: ${
+            connectors.get(connectorId)?.transactionId
+          }`
+        );
+      }
+      if (
+        connectorId > 0 &&
+        Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted)
+      ) {
+        this.initializeConnectorStatus(connectors.get(connectorId));
       }
     }
   }
@@ -1359,28 +1408,19 @@ export class ChargingStation {
         evsesConfigChanged && this.evses.clear();
         this.evsesConfigurationHash = evsesConfigHash;
         for (const evse in stationInfo?.Evses) {
-          const evseId = Utils.convertToInt(evse);
-          this.evses.set(evseId, Utils.cloneObject<EvseStatus>(stationInfo?.Evses[evse]));
-          this.evses.get(evseId).availability = AvailabilityType.Operative;
+          this.evses.set(Utils.convertToInt(evse), {
+            connectors: this.buildConnectorsMap(stationInfo?.Evses[evse]?.Connectors),
+            availability: AvailabilityType.Operative,
+          });
+          this.initializeConnectorsMapStatus(this.evses.get(Utils.convertToInt(evse))?.connectors);
         }
       }
     } else {
-      if (this.connectors.size === 0) {
-        const logMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no evses configuration defined`;
-        logger.error(`${this.logPrefix()} ${logMsg}`);
-        throw new BaseError(logMsg);
-      }
-      logger.info(
+      logger.warn(
         `${this.logPrefix()} Charging station information from template ${
           this.templateFile
-        } with no evses configuration defined, mapping one connector to one evse`
+        } with no evses configuration defined, using already defined evses`
       );
-      for (const [connectorId, connectorStatus] of this.connectors) {
-        this.evses.set(connectorId, {
-          connectorIds: [connectorId],
-          availability: connectorStatus.availability,
-        });
-      }
     }
   }
 
@@ -2101,12 +2141,12 @@ export class ChargingStation {
     return this.getTemplateFromFile()?.AutomaticTransactionGenerator;
   }
 
-  private initializeConnectorStatus(connectorId: number): void {
-    this.getConnectorStatus(connectorId).idTagLocalAuthorized = false;
-    this.getConnectorStatus(connectorId).idTagAuthorized = false;
-    this.getConnectorStatus(connectorId).transactionRemoteStarted = false;
-    this.getConnectorStatus(connectorId).transactionStarted = false;
-    this.getConnectorStatus(connectorId).energyActiveImportRegisterValue = 0;
-    this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
+  private initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
+    connectorStatus.idTagLocalAuthorized = false;
+    connectorStatus.idTagAuthorized = false;
+    connectorStatus.transactionRemoteStarted = false;
+    connectorStatus.transactionStarted = false;
+    connectorStatus.energyActiveImportRegisterValue = 0;
+    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
   }
 }
index bcedfb3a3737311ba4426febfbe05656fd023cc1..e2e9821e28c915804c7a9aec4bac79468023e956 100644 (file)
@@ -17,6 +17,7 @@ import {
   type ChargingSchedulePeriod,
   type ChargingStationInfo,
   type ChargingStationTemplate,
+  type ConnectorStatus,
   CurrentType,
   type OCPP16BootNotificationRequest,
   type OCPP20BootNotificationRequest,
@@ -92,12 +93,11 @@ export class ChargingStationUtils {
     return true;
   }
 
-  public static getTemplateMaxNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
-    const templateConnectors = stationTemplate?.Connectors;
-    if (!templateConnectors) {
+  public static getMaxNumberOfConnectors(connectors: Record<string, ConnectorStatus>): number {
+    if (!connectors) {
       return -1;
     }
-    return Object.keys(templateConnectors).length;
+    return Object.keys(connectors).length;
   }
 
   public static checkTemplateMaxConnectors(
@@ -124,10 +124,20 @@ export class ChargingStationUtils {
         numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
     } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) {
       configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
-    } else {
+    } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
       configuredMaxConnectors = stationTemplate?.Connectors[0]
-        ? ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate) - 1
-        : ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate);
+        ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
+        : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors);
+    } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
+      configuredMaxConnectors = 0;
+      for (const evse in stationTemplate.Evses) {
+        if (evse === '0') {
+          continue;
+        }
+        configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
+          stationTemplate.Evses[evse].Connectors
+        );
+      }
     }
     return configuredMaxConnectors;
   }
index 4e04c84eeef1f94767501c8e3663ec322e2436aa..200307ab2758eab00b0ce911b892708efe362fb2 100644 (file)
@@ -6,7 +6,7 @@ import type {
   AutomaticTransactionGeneratorConfiguration,
   ChargingStationOcppConfiguration,
   ConnectorStatus,
-  EvseStatus,
+  EvseTemplate,
   FirmwareStatus,
   IncomingRequestCommand,
   MessageTrigger,
@@ -113,6 +113,6 @@ export type ChargingStationTemplate = {
   messageTriggerSupport?: Record<MessageTrigger, boolean>;
   Configuration?: ChargingStationOcppConfiguration;
   AutomaticTransactionGenerator?: AutomaticTransactionGeneratorConfiguration;
-  Evses?: Record<string, EvseStatus>;
+  Evses?: Record<string, EvseTemplate>;
   Connectors: Record<string, ConnectorStatus>;
 };
diff --git a/src/types/Evse.ts b/src/types/Evse.ts
new file mode 100644 (file)
index 0000000..275969b
--- /dev/null
@@ -0,0 +1,10 @@
+import type { AvailabilityType, ConnectorStatus } from './internal';
+
+export type EvseTemplate = {
+  Connectors: Record<string, ConnectorStatus>;
+};
+
+export type EvseStatus = {
+  connectors: Map<number, ConnectorStatus>;
+  availability: AvailabilityType;
+};
diff --git a/src/types/EvseStatus.ts b/src/types/EvseStatus.ts
deleted file mode 100644 (file)
index f12ff7c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { AvailabilityType } from './internal';
-
-export type EvseStatus = {
-  connectorIds: number[];
-  availability: AvailabilityType;
-};
index 576dca54890222f91460d753bfedca304091aacc..86151c8f27dd8c25c13d957860d3de7b45fabf19 100644 (file)
@@ -37,7 +37,7 @@ export * from './ChargingStationOcppConfiguration';
 export * from './ChargingStationTemplate';
 export * from './ChargingStationWorker';
 export * from './ConfigurationData';
-export type { EvseStatus } from './EvseStatus';
+export type { EvseTemplate, EvseStatus } from './Evse';
 export type { ConnectorStatus } from './ConnectorStatus';
 export type { EmptyObject } from './EmptyObject';
 export type { HandleErrorParams } from './Error';