fix: fix return at getting connector status with evses
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 96bf6c1b3370fc29a772fc5baa01d5ef172c5509..b52fb585a63c226b5998ea444158d0496c24a0c2 100644 (file)
@@ -46,7 +46,6 @@ import {
   type ChargingStationInfo,
   type ChargingStationOcppConfiguration,
   type ChargingStationTemplate,
-  ConnectorPhaseRotation,
   type ConnectorStatus,
   ConnectorStatusEnum,
   CurrentType,
@@ -54,6 +53,7 @@ import {
   type ErrorResponse,
   ErrorType,
   type EvseStatus,
+  type EvseStatusConfiguration,
   FileType,
   FirmwareStatus,
   type FirmwareStatusNotificationRequest,
@@ -151,6 +151,10 @@ export class ChargingStation {
     this.initialize();
   }
 
+  public get hasEvses(): boolean {
+    return this.connectors.size === 0 && this.evses.size > 0;
+  }
+
   private get wsConnectionUrl(): URL {
     return new URL(
       `${
@@ -240,16 +244,52 @@ export class ChargingStation {
     return this.getConnectorStatus(0)?.availability === AvailabilityType.Operative;
   }
 
-  public isConnectorAvailable(id: number): boolean {
-    return id > 0 && this.getConnectorStatus(id)?.availability === AvailabilityType.Operative;
+  public hasConnector(connectorId: number): boolean {
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        if (evseStatus.connectors.has(connectorId)) {
+          return true;
+        }
+      }
+      return false;
+    }
+    return this.connectors.has(connectorId);
+  }
+
+  public isConnectorAvailable(connectorId: number): boolean {
+    return (
+      connectorId > 0 &&
+      this.getConnectorStatus(connectorId)?.availability === AvailabilityType.Operative
+    );
   }
 
   public getNumberOfConnectors(): number {
-    return this.connectors.get(0) ? this.connectors.size - 1 : this.connectors.size;
+    if (this.hasEvses) {
+      let numberOfConnectors = 0;
+      for (const [evseId, evseStatus] of this.evses) {
+        if (evseId > 0) {
+          numberOfConnectors += evseStatus.connectors.size;
+        }
+      }
+      return numberOfConnectors;
+    }
+    return this.connectors.has(0) ? this.connectors.size - 1 : this.connectors.size;
   }
 
-  public getConnectorStatus(id: number): ConnectorStatus | undefined {
-    return this.connectors.get(id);
+  public getNumberOfEvses(): number {
+    return this.evses.has(0) ? this.evses.size - 1 : this.evses.size;
+  }
+
+  public getConnectorStatus(connectorId: number): ConnectorStatus | undefined {
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        if (evseStatus.connectors.has(connectorId)) {
+          return evseStatus.connectors.get(connectorId);
+        }
+      }
+      return undefined;
+    }
+    return this.connectors.get(connectorId);
   }
 
   public getCurrentOutType(stationInfo?: ChargingStationInfo): CurrentType {
@@ -306,12 +346,22 @@ export class ChargingStation {
   }
 
   public getTransactionIdTag(transactionId: number): string | undefined {
-    for (const connectorId of this.connectors.keys()) {
-      if (
-        connectorId > 0 &&
-        this.getConnectorStatus(connectorId)?.transactionId === transactionId
-      ) {
-        return this.getConnectorStatus(connectorId)?.transactionIdTag;
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        for (const connectorStatus of evseStatus.connectors.values()) {
+          if (connectorStatus.transactionId === transactionId) {
+            return connectorStatus.transactionIdTag;
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (
+          connectorId > 0 &&
+          this.getConnectorStatus(connectorId)?.transactionId === transactionId
+        ) {
+          return this.getConnectorStatus(connectorId)?.transactionIdTag;
+        }
       }
     }
   }
@@ -345,12 +395,22 @@ export class ChargingStation {
   }
 
   public getConnectorIdByTransactionId(transactionId: number): number | undefined {
-    for (const connectorId of this.connectors.keys()) {
-      if (
-        connectorId > 0 &&
-        this.getConnectorStatus(connectorId)?.transactionId === transactionId
-      ) {
-        return connectorId;
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+          if (connectorStatus.transactionId === transactionId) {
+            return connectorId;
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (
+          connectorId > 0 &&
+          this.getConnectorStatus(connectorId)?.transactionId === transactionId
+        ) {
+          return connectorId;
+        }
       }
     }
   }
@@ -534,6 +594,12 @@ export class ChargingStation {
     }
   }
 
+  public stopMeterValues(connectorId: number) {
+    if (this.getConnectorStatus(connectorId)?.transactionSetInterval) {
+      clearInterval(this.getConnectorStatus(connectorId)?.transactionSetInterval);
+    }
+  }
+
   public start(): void {
     if (this.started === false) {
       if (this.starting === false) {
@@ -625,23 +691,8 @@ export class ChargingStation {
 
   public saveOcppConfiguration(): void {
     if (this.getOcppPersistentConfiguration()) {
-      this.saveConfiguration();
-    }
-  }
-
-  public resetConnectorStatus(connectorId: number): void {
-    this.getConnectorStatus(connectorId).idTagLocalAuthorized = false;
-    this.getConnectorStatus(connectorId).idTagAuthorized = false;
-    this.getConnectorStatus(connectorId).transactionRemoteStarted = false;
-    this.getConnectorStatus(connectorId).transactionStarted = false;
-    delete this.getConnectorStatus(connectorId)?.localAuthorizeIdTag;
-    delete this.getConnectorStatus(connectorId)?.authorizeIdTag;
-    delete this.getConnectorStatus(connectorId)?.transactionId;
-    delete this.getConnectorStatus(connectorId)?.transactionIdTag;
-    this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
-    delete this.getConnectorStatus(connectorId)?.transactionBeginMeterValue;
-    this.stopMeterValues(connectorId);
-    parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+      this.saveConfiguration({ stationInfo: false, connectors: false, evses: false });
+    }
   }
 
   public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean | undefined {
@@ -922,47 +973,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;
@@ -1000,7 +1012,7 @@ export class ChargingStation {
 
   private saveStationInfo(): void {
     if (this.getStationInfoPersistentConfiguration()) {
-      this.saveConfiguration();
+      this.saveConfiguration({ ocppConfiguration: false, connectors: false, evses: false });
     }
   }
 
@@ -1043,8 +1055,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(
@@ -1195,24 +1208,26 @@ export class ChargingStation {
         StandardParametersKey.ConnectorPhaseRotation
       )
     ) {
-      const connectorPhaseRotation = [];
-      for (const connectorId of this.connectors.keys()) {
-        // AC/DC
-        if (connectorId === 0 && this.getNumberOfPhases() === 0) {
-          connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`);
-        } else if (connectorId > 0 && this.getNumberOfPhases() === 0) {
-          connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`);
-          // AC
-        } else if (connectorId > 0 && this.getNumberOfPhases() === 1) {
-          connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`);
-        } else if (connectorId > 0 && this.getNumberOfPhases() === 3) {
-          connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`);
+      const connectorsPhaseRotation: string[] = [];
+      if (this.hasEvses) {
+        for (const evseStatus of this.evses.values()) {
+          for (const connectorId of evseStatus.connectors.keys()) {
+            connectorsPhaseRotation.push(
+              ChargingStationUtils.getPhaseRotationValue(connectorId, this.getNumberOfPhases())
+            );
+          }
+        }
+      } else {
+        for (const connectorId of this.connectors.keys()) {
+          connectorsPhaseRotation.push(
+            ChargingStationUtils.getPhaseRotationValue(connectorId, this.getNumberOfPhases())
+          );
         }
       }
       ChargingStationConfigurationUtils.addConfigurationKey(
         this,
         StandardParametersKey.ConnectorPhaseRotation,
-        connectorPhaseRotation.toString()
+        connectorsPhaseRotation.toString()
       );
     }
     if (
@@ -1258,10 +1273,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}`);
@@ -1275,6 +1303,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()}`)
@@ -1284,44 +1319,58 @@ export class ChargingStation {
       if (this.connectors?.size === 0 || connectorsConfigChanged) {
         connectorsConfigChanged && this.connectors.clear();
         this.connectorsConfigurationHash = connectorsConfigHash;
-        // 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
-          ) {
-            this.checkStationInfoConnectorStatus(lastConnectorId, connectorStatus);
-            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 = [];
-            }
-          }
-        }
-        // Generate all 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()];
-            this.checkStationInfoConnectorStatus(randConnectorId, connectorStatus);
-            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 = [];
+        ChargingStationUtils.checkTemplateMaxConnectors(
+          templateMaxConnectors,
+          this.templateFile,
+          this.logPrefix()
+        );
+        const templateMaxAvailableConnectors = stationInfo?.Connectors[0]
+          ? templateMaxConnectors - 1
+          : templateMaxConnectors;
+        if (
+          configuredMaxConnectors > templateMaxAvailableConnectors &&
+          !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;
+        }
+        if (templateMaxConnectors > 0) {
+          for (let connectorId = 0; connectorId <= configuredMaxConnectors; connectorId++) {
+            if (
+              connectorId === 0 &&
+              (!stationInfo?.Connectors[connectorId] ||
+                this.getUseConnectorId0(stationInfo) === false)
+            ) {
+              continue;
             }
+            const templateConnectorId =
+              connectorId > 0 && stationInfo?.randomConnectors
+                ? Utils.getRandomInteger(templateMaxAvailableConnectors, 1)
+                : connectorId;
+            const connectorStatus = stationInfo?.Connectors[templateConnectorId];
+            ChargingStationUtils.checkStationInfoConnectorStatus(
+              templateConnectorId,
+              connectorStatus,
+              this.logPrefix(),
+              this.templateFile
+            );
+            this.connectors.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
           }
+          ChargingStationUtils.initializeConnectorsMapStatus(this.connectors, this.logPrefix());
+          this.saveConnectorsStatus();
+        } else {
+          logger.warn(
+            `${this.logPrefix()} Charging station information from template ${
+              this.templateFile
+            } with no connectors configuration defined, cannot create connectors`
+          );
         }
       }
     } else {
@@ -1331,64 +1380,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)
-      ) {
-        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));
-      }
-    }
   }
 
   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(
@@ -1397,6 +1395,13 @@ export class ChargingStation {
         } with no evse id 0 configuration`
       );
     }
+    if (!stationInfo?.Evses[0]?.Connectors[0]) {
+      logger.warn(
+        `${this.logPrefix()} Charging station information from template ${
+          this.templateFile
+        } with evse id 0 with no connector id 0 configuration`
+      );
+    }
     if (stationInfo?.Evses) {
       const evsesConfigHash = crypto
         .createHash(Constants.DEFAULT_HASH_ALGORITHM)
@@ -1407,12 +1412,30 @@ 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: this.buildConnectorsMap(stationInfo?.Evses[evse]?.Connectors),
-            availability: AvailabilityType.Operative,
-          });
-          this.initializeConnectorsMapStatus(this.evses.get(Utils.convertToInt(evse))?.connectors);
+        const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationInfo?.Evses);
+        if (templateMaxEvses > 0) {
+          for (const evse in stationInfo.Evses) {
+            const evseId = Utils.convertToInt(evse);
+            this.evses.set(evseId, {
+              connectors: ChargingStationUtils.buildConnectorsMap(
+                stationInfo?.Evses[evse]?.Connectors,
+                this.logPrefix(),
+                this.templateFile
+              ),
+              availability: AvailabilityType.Operative,
+            });
+            ChargingStationUtils.initializeConnectorsMapStatus(
+              this.evses.get(evseId)?.connectors,
+              this.logPrefix()
+            );
+          }
+          this.saveEvsesStatus();
+        } else {
+          logger.warn(
+            `${this.logPrefix()} Charging station information from template ${
+              this.templateFile
+            } with no evses configuration defined, cannot create evses`
+          );
         }
       }
     } else {
@@ -1424,20 +1447,6 @@ export class ChargingStation {
     }
   }
 
-  private checkStationInfoConnectorStatus(
-    connectorId: number,
-    connectorStatus: ConnectorStatus
-  ): void {
-    if (!Utils.isNullOrUndefined(connectorStatus?.status)) {
-      logger.warn(
-        `${this.logPrefix()} Charging station information from template ${
-          this.templateFile
-        } with connector ${connectorId} status configuration defined, undefine it`
-      );
-      delete connectorStatus.status;
-    }
-  }
-
   private getConfigurationFromFile(): ChargingStationConfiguration | undefined {
     let configuration: ChargingStationConfiguration | undefined;
     if (this.configurationFile && fs.existsSync(this.configurationFile)) {
@@ -1468,17 +1477,62 @@ export class ChargingStation {
     return configuration;
   }
 
-  private saveConfiguration(): void {
+  private saveConnectorsStatus() {
+    if (this.getOcppPersistentConfiguration()) {
+      this.saveConfiguration({ stationInfo: false, ocppConfiguration: false, evses: false });
+    }
+  }
+
+  private saveEvsesStatus() {
+    if (this.getOcppPersistentConfiguration()) {
+      this.saveConfiguration({ stationInfo: false, ocppConfiguration: false, connectors: false });
+    }
+  }
+
+  private saveConfiguration(
+    params: {
+      stationInfo?: boolean;
+      ocppConfiguration?: boolean;
+      connectors?: boolean;
+      evses?: boolean;
+    } = { stationInfo: true, ocppConfiguration: true, connectors: true, evses: true }
+  ): void {
     if (this.configurationFile) {
+      params = {
+        ...params,
+        ...{ stationInfo: true, ocppConfiguration: true, connectors: true, evses: true },
+      };
       try {
         if (!fs.existsSync(path.dirname(this.configurationFile))) {
           fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
         }
         const configurationData: ChargingStationConfiguration =
           Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
-        this.ocppConfiguration?.configurationKey &&
-          (configurationData.configurationKey = this.ocppConfiguration.configurationKey);
-        this.stationInfo && (configurationData.stationInfo = this.stationInfo);
+        if (params.stationInfo && this.stationInfo) {
+          configurationData.stationInfo = this.stationInfo;
+        }
+        if (params.ocppConfiguration && this.ocppConfiguration?.configurationKey) {
+          configurationData.configurationKey = this.ocppConfiguration.configurationKey;
+        }
+        if (params.connectors && this.connectors.size > 0) {
+          configurationData.connectorsStatus = [...this.connectors.values()].map(
+            // eslint-disable-next-line @typescript-eslint/no-unused-vars
+            ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest
+          );
+        }
+        if (params.evses && this.evses.size > 0) {
+          configurationData.evsesStatus = [...this.evses.values()].map((evseStatus) => {
+            const status = {
+              ...evseStatus,
+              connectorsStatus: [...evseStatus.connectors.values()].map(
+                // eslint-disable-next-line @typescript-eslint/no-unused-vars
+                ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest
+              ),
+            };
+            delete status.connectors;
+            return status as EvseStatusConfiguration;
+          });
+        }
         delete configurationData.configurationHash;
         const configurationHash = crypto
           .createHash(Constants.DEFAULT_HASH_ALGORITHM)
@@ -1808,18 +1862,38 @@ export class ChargingStation {
 
   private getNumberOfRunningTransactions(): number {
     let trxCount = 0;
-    for (const connectorId of this.connectors.keys()) {
-      if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
-        trxCount++;
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        for (const connectorStatus of evseStatus.connectors.values()) {
+          if (connectorStatus.transactionStarted === true) {
+            trxCount++;
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
+          trxCount++;
+        }
       }
     }
     return trxCount;
   }
 
   private async stopRunningTransactions(reason = StopTransactionReason.NONE): Promise<void> {
-    for (const connectorId of this.connectors.keys()) {
-      if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
-        await this.stopTransactionOnConnector(connectorId, reason);
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+          if (connectorStatus.transactionStarted === true) {
+            await this.stopTransactionOnConnector(connectorId, reason);
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
+          await this.stopTransactionOnConnector(connectorId, reason);
+        }
       }
     }
   }
@@ -1918,30 +1992,34 @@ export class ChargingStation {
     // Start heartbeat
     this.startHeartbeat();
     // Initialize connectors status
-    for (const connectorId of this.connectors.keys()) {
-      let connectorStatus: ConnectorStatusEnum | undefined;
-      if (connectorId === 0) {
-        continue;
-      } else if (
-        !this.getConnectorStatus(connectorId)?.status &&
-        (this.isChargingStationAvailable() === false ||
-          this.isConnectorAvailable(connectorId) === false)
-      ) {
-        connectorStatus = ConnectorStatusEnum.Unavailable;
-      } else if (
-        !this.getConnectorStatus(connectorId)?.status &&
-        this.getConnectorStatus(connectorId)?.bootStatus
-      ) {
-        // Set boot status in template at startup
-        connectorStatus = this.getConnectorStatus(connectorId)?.bootStatus;
-      } else if (this.getConnectorStatus(connectorId)?.status) {
-        // Set previous status at startup
-        connectorStatus = this.getConnectorStatus(connectorId)?.status;
-      } else {
-        // Set default status
-        connectorStatus = ConnectorStatusEnum.Available;
+    if (this.hasEvses) {
+      for (const [evseId, evseStatus] of this.evses) {
+        if (evseId > 0) {
+          for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+            const connectorBootStatus = ChargingStationUtils.getBootConnectorStatus(
+              this,
+              connectorId,
+              connectorStatus
+            );
+            await OCPPServiceUtils.sendAndSetConnectorStatus(
+              this,
+              connectorId,
+              connectorBootStatus
+            );
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (connectorId > 0) {
+          const connectorBootStatus = ChargingStationUtils.getBootConnectorStatus(
+            this,
+            connectorId,
+            this.getConnectorStatus(connectorId)
+          );
+          await OCPPServiceUtils.sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
+        }
       }
-      await OCPPServiceUtils.sendAndSetConnectorStatus(this, connectorId, connectorStatus);
     }
     if (this.stationInfo?.firmwareStatus === FirmwareStatus.Installing) {
       await this.ocppRequestService.requestHandler<
@@ -1973,21 +2051,43 @@ export class ChargingStation {
     } else {
       await this.stopRunningTransactions(reason);
     }
-    for (const connectorId of this.connectors.keys()) {
-      if (connectorId > 0) {
-        await this.ocppRequestService.requestHandler<
-          StatusNotificationRequest,
-          StatusNotificationResponse
-        >(
-          this,
-          RequestCommand.STATUS_NOTIFICATION,
-          OCPPServiceUtils.buildStatusNotificationRequest(
+    if (this.hasEvses) {
+      for (const [evseId, evseStatus] of this.evses) {
+        if (evseId > 0) {
+          for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+            await this.ocppRequestService.requestHandler<
+              StatusNotificationRequest,
+              StatusNotificationResponse
+            >(
+              this,
+              RequestCommand.STATUS_NOTIFICATION,
+              OCPPServiceUtils.buildStatusNotificationRequest(
+                this,
+                connectorId,
+                ConnectorStatusEnum.Unavailable
+              )
+            );
+            delete connectorStatus?.status;
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (connectorId > 0) {
+          await this.ocppRequestService.requestHandler<
+            StatusNotificationRequest,
+            StatusNotificationResponse
+          >(
             this,
-            connectorId,
-            ConnectorStatusEnum.Unavailable
-          )
-        );
-        delete this.getConnectorStatus(connectorId)?.status;
+            RequestCommand.STATUS_NOTIFICATION,
+            OCPPServiceUtils.buildStatusNotificationRequest(
+              this,
+              connectorId,
+              ConnectorStatusEnum.Unavailable
+            )
+          );
+          delete this.getConnectorStatus(connectorId)?.status;
+        }
       }
     }
   }
@@ -2076,12 +2176,6 @@ export class ChargingStation {
     }
   }
 
-  private stopMeterValues(connectorId: number) {
-    if (this.getConnectorStatus(connectorId)?.transactionSetInterval) {
-      clearInterval(this.getConnectorStatus(connectorId)?.transactionSetInterval);
-    }
-  }
-
   private getReconnectExponentialDelay(): boolean {
     return this.stationInfo?.reconnectExponentialDelay ?? false;
   }
@@ -2140,13 +2234,4 @@ export class ChargingStation {
     | undefined {
     return this.getTemplateFromFile()?.AutomaticTransactionGenerator;
   }
-
-  private initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
-    connectorStatus.idTagLocalAuthorized = false;
-    connectorStatus.idTagAuthorized = false;
-    connectorStatus.transactionRemoteStarted = false;
-    connectorStatus.transactionStarted = false;
-    connectorStatus.energyActiveImportRegisterValue = 0;
-    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
-  }
 }