UI server: permit to address all charging stations
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index a47bc68182a77de166b1dc9fd273a7d31d59265b..89fffc3bffc03b3399837d211a9d8d31ea5411c3 100644 (file)
@@ -84,14 +84,14 @@ import type OCPPRequestService from './ocpp/OCPPRequestService';
 import SharedLRUCache from './SharedLRUCache';
 
 export default class ChargingStation {
-  public hashId!: string;
   public readonly templateFile: string;
-  public authorizedTagsCache: AuthorizedTagsCache;
   public stationInfo!: ChargingStationInfo;
   public stopped: boolean;
-  public readonly connectors: Map<number, ConnectorStatus>;
+  public authorizedTagsCache: AuthorizedTagsCache;
+  public automaticTransactionGenerator!: AutomaticTransactionGenerator;
   public ocppConfiguration!: ChargingStationOcppConfiguration;
   public wsConnection!: WebSocket;
+  public readonly connectors: Map<number, ConnectorStatus>;
   public readonly requests: Map<string, CachedRequest>;
   public performanceStatistics!: PerformanceStatistics;
   public heartbeatSetInterval!: NodeJS.Timeout;
@@ -110,22 +110,21 @@ export default class ChargingStation {
   private autoReconnectRetryCount: number;
   private templateFileWatcher!: fs.FSWatcher;
   private readonly sharedLRUCache: SharedLRUCache;
-  private automaticTransactionGenerator!: AutomaticTransactionGenerator;
   private webSocketPingSetInterval!: NodeJS.Timeout;
   private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel;
 
   constructor(index: number, templateFile: string) {
     this.index = index;
     this.templateFile = templateFile;
-    this.stopped = false;
-    this.wsConnectionRestarted = false;
-    this.autoReconnectRetryCount = 0;
-    this.sharedLRUCache = SharedLRUCache.getInstance();
-    this.authorizedTagsCache = AuthorizedTagsCache.getInstance();
     this.connectors = new Map<number, ConnectorStatus>();
     this.requests = new Map<string, CachedRequest>();
     this.messageBuffer = new Set<string>();
+    this.sharedLRUCache = SharedLRUCache.getInstance();
+    this.authorizedTagsCache = AuthorizedTagsCache.getInstance();
     this.chargingStationWorkerBroadcastChannel = new ChargingStationWorkerBroadcastChannel(this);
+    this.stopped = false;
+    this.wsConnectionRestarted = false;
+    this.autoReconnectRetryCount = 0;
 
     this.initialize();
   }
@@ -332,22 +331,18 @@ export default class ChargingStation {
     }
   }
 
-  public getEnergyActiveImportRegisterByTransactionId(transactionId: number): number {
-    const transactionConnectorStatus = this.getConnectorStatus(
-      this.getConnectorIdByTransactionId(transactionId)
+  public getEnergyActiveImportRegisterByTransactionId(
+    transactionId: number,
+    meterStop = false
+  ): number {
+    return this.getEnergyActiveImportRegister(
+      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)),
+      meterStop
     );
-    if (this.getMeteringPerTransaction()) {
-      return transactionConnectorStatus?.transactionEnergyActiveImportRegisterValue ?? 0;
-    }
-    return transactionConnectorStatus?.energyActiveImportRegisterValue ?? 0;
   }
 
   public getEnergyActiveImportRegisterByConnectorId(connectorId: number): number {
-    const connectorStatus = this.getConnectorStatus(connectorId);
-    if (this.getMeteringPerTransaction()) {
-      return connectorStatus?.transactionEnergyActiveImportRegisterValue ?? 0;
-    }
-    return connectorStatus?.energyActiveImportRegisterValue ?? 0;
+    return this.getEnergyActiveImportRegister(this.getConnectorStatus(connectorId));
   }
 
   public getAuthorizeRemoteTxRequests(): boolean {
@@ -748,21 +743,29 @@ export default class ChargingStation {
     }
   }
 
-  public startAutomaticTransactionGenerator(): void {
+  public startAutomaticTransactionGenerator(connectorIds?: number[]): void {
     if (!this.automaticTransactionGenerator) {
       this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance(
         this.getAutomaticTransactionGeneratorConfigurationFromTemplate(),
         this
       );
     }
-    if (!this.automaticTransactionGenerator.started) {
+    if (!Utils.isEmptyArray(connectorIds)) {
+      for (const connectorId of connectorIds) {
+        this.automaticTransactionGenerator.startConnector(connectorId);
+      }
+    } else {
       this.automaticTransactionGenerator.start();
     }
   }
 
-  public stopAutomaticTransactionGenerator(): void {
-    if (this.automaticTransactionGenerator?.started) {
-      this.automaticTransactionGenerator.stop();
+  public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
+    if (!Utils.isEmptyArray(connectorIds)) {
+      for (const connectorId of connectorIds) {
+        this.automaticTransactionGenerator?.stopConnector(connectorId);
+      }
+    } else {
+      this.automaticTransactionGenerator?.stop();
       this.automaticTransactionGenerator = null;
     }
   }
@@ -841,6 +844,7 @@ export default class ChargingStation {
     );
     const stationInfo: ChargingStationInfo =
       ChargingStationUtils.stationTemplateToStationInfo(stationTemplate);
+    stationInfo.hashId = ChargingStationUtils.getHashId(this.index, stationTemplate);
     stationInfo.chargingStationId = ChargingStationUtils.getChargingStationId(
       this.index,
       stationTemplate
@@ -950,20 +954,19 @@ export default class ChargingStation {
   }
 
   private initialize(): void {
-    this.hashId = ChargingStationUtils.getHashId(this.index, this.getTemplateFromFile());
-    logger.info(`${this.logPrefix()} Charging station hashId '${this.hashId}'`);
     this.configurationFile = path.join(
       path.dirname(this.templateFile.replace('station-templates', 'configurations')),
-      this.hashId + '.json'
+      ChargingStationUtils.getHashId(this.index, this.getTemplateFromFile()) + '.json'
     );
     this.stationInfo = this.getStationInfo();
     this.saveStationInfo();
+    logger.info(`${this.logPrefix()} Charging station hashId '${this.stationInfo.hashId}'`);
     // Avoid duplication of connectors related information in RAM
     this.stationInfo?.Connectors && delete this.stationInfo.Connectors;
     this.configuredSupervisionUrl = this.getConfiguredSupervisionUrl();
     if (this.getEnableStatistics()) {
       this.performanceStatistics = PerformanceStatistics.getInstance(
-        this.hashId,
+        this.stationInfo.hashId,
         this.stationInfo.chargingStationId,
         this.configuredSupervisionUrl
       );
@@ -1578,6 +1581,24 @@ export default class ChargingStation {
     logger.error(this.logPrefix() + ' WebSocket error:', error);
   }
 
+  private getEnergyActiveImportRegister(
+    connectorStatus: ConnectorStatus,
+    meterStop = false
+  ): number {
+    if (this.getMeteringPerTransaction()) {
+      return (
+        (meterStop === true
+          ? Math.round(connectorStatus?.transactionEnergyActiveImportRegisterValue)
+          : connectorStatus?.transactionEnergyActiveImportRegisterValue) ?? 0
+      );
+    }
+    return (
+      (meterStop === true
+        ? Math.round(connectorStatus?.energyActiveImportRegisterValue)
+        : connectorStatus?.energyActiveImportRegisterValue) ?? 0
+    );
+  }
+
   private getUseConnectorId0(stationInfo?: ChargingStationInfo): boolean | undefined {
     const localStationInfo = stationInfo ?? this.stationInfo;
     return !Utils.isUndefined(localStationInfo.useConnectorId0)
@@ -1812,7 +1833,7 @@ export default class ChargingStation {
               StopTransactionResponse
             >(this, RequestCommand.STOP_TRANSACTION, {
               transactionId,
-              meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId),
+              meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId, true),
               idTag: this.getTransactionIdTag(transactionId),
               reason,
             });