// 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 {
AuthorizationStatus,
+ ChargingStationEvents,
RequestCommand,
type StartTransactionRequest,
type StartTransactionResponse,
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<
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
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)}`)
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(
)}`
)
logger.debug(
- `${this.logPrefix(connectorId)} connector status: %j`,
+ `${this.logPrefix(connectorId)} stopped with connector status: %j`,
this.connectorsStatus.get(connectorId)
)
+ this.chargingStation.emit(ChargingStationEvents.updated)
}
private setStartConnectorStatus (
this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.connectorsStatus.get(connectorId)!.start = true
+ this.chargingStation.emit(ChargingStationEvents.updated)
}
private canStartConnector (connectorId: number): boolean {
)
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
}
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
}
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) {
logger.info(startTransactionLogMsg)
// Start transaction
startResponse = await this.chargingStation.ocppRequestService.requestHandler<
- StartTransactionRequest,
+ Partial<StartTransactionRequest>,
StartTransactionResponse
>(this.chargingStation, RequestCommand.START_TRANSACTION, {
connectorId,
logger.info(startTransactionLogMsg)
// Start transaction
startResponse = await this.chargingStation.ocppRequestService.requestHandler<
- StartTransactionRequest,
+ Partial<StartTransactionRequest>,
StartTransactionResponse
>(this.chargingStation, RequestCommand.START_TRANSACTION, {
connectorId,
}
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