fix: add sanity check in ATG on connector id
[e-mobility-charging-stations-simulator.git] / src / charging-station / AutomaticTransactionGenerator.ts
index adf38e67b4591c0dae62a6b76827556bbba5382f..0eb47381876d833aef74796f6471a8af4bcb8c35 100644 (file)
@@ -1,11 +1,9 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
+import { randomInt } from 'node:crypto'
+
 import { hoursToMilliseconds, secondsToMilliseconds } from 'date-fns'
 
-import type { ChargingStation } from './ChargingStation.js'
-import { checkChargingStation } from './Helpers.js'
-import { IdTagsCache } from './IdTagsCache.js'
-import { isIdTagAuthorized } from './ocpp/index.js'
 import { BaseError } from '../exception/index.js'
 import { PerformanceStatistics } from '../performance/index.js'
 import {
@@ -18,17 +16,20 @@ import {
   type StopTransactionResponse
 } from '../types/index.js'
 import {
-  Constants,
   clone,
+  Constants,
   convertToDate,
   formatDurationMilliSeconds,
-  getRandomInteger,
   isValidDate,
-  logPrefix,
   logger,
+  logPrefix,
   secureRandom,
   sleep
 } from '../utils/index.js'
+import type { ChargingStation } from './ChargingStation.js'
+import { checkChargingStation } from './Helpers.js'
+import { IdTagsCache } from './IdTagsCache.js'
+import { isIdTagAuthorized } from './ocpp/index.js'
 
 export class AutomaticTransactionGenerator {
   private static readonly instances: Map<string, AutomaticTransactionGenerator> = new Map<
@@ -66,6 +67,11 @@ export class AutomaticTransactionGenerator {
     return AutomaticTransactionGenerator.instances.get(chargingStation.stationInfo!.hashId)
   }
 
+  public static deleteInstance (chargingStation: ChargingStation): boolean {
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    return AutomaticTransactionGenerator.instances.delete(chargingStation.stationInfo!.hashId)
+  }
+
   public start (stopAbsoluteDuration?: boolean): void {
     if (!checkChargingStation(this.chargingStation, this.logPrefix())) {
       return
@@ -194,11 +200,11 @@ export class AutomaticTransactionGenerator {
         break
       }
       const wait = secondsToMilliseconds(
-        getRandomInteger(
+        randomInt(
           this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
-            ?.maxDelayBetweenTwoTransactions,
+            ?.minDelayBetweenTwoTransactions,
           this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
-            ?.minDelayBetweenTwoTransactions
+            ?.maxDelayBetweenTwoTransactions
         )
       )
       logger.info(`${this.logPrefix(connectorId)} waiting for ${formatDurationMilliSeconds(wait)}`)
@@ -216,9 +222,9 @@ export class AutomaticTransactionGenerator {
         if (startResponse?.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
           // Wait until end of transaction
           const waitTrxEnd = secondsToMilliseconds(
-            getRandomInteger(
-              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.maxDuration,
-              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.minDuration
+            randomInt(
+              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.minDuration,
+              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.maxDuration
             )
           )
           logger.info(
@@ -324,6 +330,15 @@ export class AutomaticTransactionGenerator {
       )
       return false
     }
+    const connectorStatus = this.chargingStation.getConnectorStatus(connectorId)
+    if (connectorStatus?.transactionStarted === true) {
+      logger.info(
+        `${this.logPrefix(connectorId)} entered in transaction loop while a transaction ${
+          connectorStatus.transactionId
+        } is already started on connector ${connectorId}`
+      )
+      return false
+    }
     return true
   }
 
@@ -363,9 +378,9 @@ export class AutomaticTransactionGenerator {
     while (connectorStatus?.transactionStarted === true) {
       if (!logged) {
         logger.info(
-          `${this.logPrefix(
-            connectorId
-          )} transaction loop waiting for running transaction ${connectorStatus.transactionId} on connector ${connectorId} to be stopped`
+          `${this.logPrefix(connectorId)} transaction loop waiting for started transaction ${
+            connectorStatus.transactionId
+          } on connector ${connectorId} to be stopped`
         )
         logged = true
       }
@@ -393,15 +408,21 @@ export class AutomaticTransactionGenerator {
 
   private getConnectorStatus (connectorId: number): Status {
     const statusIndex = connectorId - 1
+    if (statusIndex < 0) {
+      logger.error(`${this.logPrefix(connectorId)} invalid connector id`)
+      throw new BaseError(`Invalid connector id ${connectorId}`)
+    }
     let connectorStatus: Status | undefined
     if (this.chargingStation.getAutomaticTransactionGeneratorStatuses()?.[statusIndex] != null) {
       connectorStatus = clone<Status>(
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         this.chargingStation.getAutomaticTransactionGeneratorStatuses()![statusIndex]
       )
-    } else if (this.chargingStation.getAutomaticTransactionGeneratorStatuses() != null) {
+    } else {
       logger.warn(
-        `${this.logPrefix(connectorId)} no status found for connector #${connectorId} in charging station configuration file. New status will be created`
+        `${this.logPrefix(
+          connectorId
+        )} no status found for connector #${connectorId} in charging station configuration file. New status will be created`
       )
     }
     if (connectorStatus != null) {
@@ -460,7 +481,7 @@ export class AutomaticTransactionGenerator {
           logger.info(startTransactionLogMsg)
           // Start transaction
           startResponse = await this.chargingStation.ocppRequestService.requestHandler<
-          StartTransactionRequest,
+          Partial<StartTransactionRequest>,
           StartTransactionResponse
           >(this.chargingStation, RequestCommand.START_TRANSACTION, {
             connectorId,
@@ -478,7 +499,7 @@ export class AutomaticTransactionGenerator {
       logger.info(startTransactionLogMsg)
       // Start transaction
       startResponse = await this.chargingStation.ocppRequestService.requestHandler<
-      StartTransactionRequest,
+      Partial<StartTransactionRequest>,
       StartTransactionResponse
       >(this.chargingStation, RequestCommand.START_TRANSACTION, {
         connectorId,
@@ -490,9 +511,11 @@ export class AutomaticTransactionGenerator {
     }
     logger.info(`${this.logPrefix(connectorId)} start transaction without an idTag`)
     startResponse = await this.chargingStation.ocppRequestService.requestHandler<
-    StartTransactionRequest,
+    Partial<StartTransactionRequest>,
     StartTransactionResponse
-    >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId })
+    >(this.chargingStation, RequestCommand.START_TRANSACTION, {
+      connectorId
+    })
     this.handleStartTransactionResponse(connectorId, startResponse)
     PerformanceStatistics.endMeasure(measureId, beginId)
     return startResponse