+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ++this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ++this.connectorsStatus.get(connectorId)!.skippedTransactions
+ logger.info(
+ `${this.logPrefix(connectorId)} skipped consecutively ${this.connectorsStatus.get(
+ connectorId
+ )?.skippedConsecutiveTransactions}/${this.connectorsStatus.get(connectorId)
+ ?.skippedTransactions} transaction(s)`
+ )
+ }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.lastRunDate = new Date()
+ }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.stoppedDate = new Date()
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} stopped on connector and lasted for ${formatDurationMilliSeconds(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.stoppedDate!.getTime() -
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.startDate!.getTime()
+ )}`
+ )
+ logger.debug(
+ `${this.logPrefix(connectorId)} connector status: %j`,
+ this.connectorsStatus.get(connectorId)
+ )
+ }
+
+ private setStartConnectorStatus (connectorId: number): void {
+ const previousRunDuration =
+ isValidTime(this.connectorsStatus.get(connectorId)?.startDate) &&
+ isValidTime(this.connectorsStatus.get(connectorId)?.lastRunDate)
+ ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.lastRunDate!.getTime() -
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.startDate!.getTime()
+ : 0
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.startDate = new Date()
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.stopDate = new Date(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.startDate!.getTime() +
+ hoursToMilliseconds(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.chargingStation.getAutomaticTransactionGeneratorConfiguration()!.stopAfterHours
+ ) -
+ previousRunDuration
+ )
+ delete this.connectorsStatus.get(connectorId)?.stoppedDate
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.connectorsStatus.get(connectorId)!.start = true
+ }
+
+ private canStartConnector (connectorId: number): boolean {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ if (new Date() > this.connectorsStatus.get(connectorId)!.stopDate!) {
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} entered in transaction loop while the ATG stop date has been reached`
+ )
+ return false
+ }
+ if (!this.chargingStation.inAcceptedState()) {
+ logger.error(
+ `${this.logPrefix(
+ connectorId
+ )} entered in transaction loop while the charging station is not in accepted state`
+ )
+ return false
+ }
+ if (!this.chargingStation.isChargingStationAvailable()) {
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} entered in transaction loop while the charging station is unavailable`
+ )
+ return false
+ }
+ if (!this.chargingStation.isConnectorAvailable(connectorId)) {
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} entered in transaction loop while the connector ${connectorId} is unavailable`
+ )
+ return false
+ }
+ return true
+ }
+
+ private async waitChargingStationAvailable (connectorId: number): Promise<void> {
+ let logged = false
+ while (!this.chargingStation.isChargingStationAvailable()) {
+ if (!logged) {
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} transaction loop waiting for charging station to be available`
+ )
+ logged = true
+ }
+ await sleep(Constants.CHARGING_STATION_ATG_AVAILABILITY_TIME)
+ }
+ }
+
+ private async waitConnectorAvailable (connectorId: number): Promise<void> {
+ let logged = false
+ while (!this.chargingStation.isConnectorAvailable(connectorId)) {
+ if (!logged) {
+ logger.info(
+ `${this.logPrefix(
+ connectorId
+ )} transaction loop waiting for connector ${connectorId} to be available`
+ )
+ logged = true
+ }
+ await sleep(Constants.CHARGING_STATION_ATG_AVAILABILITY_TIME)
+ }
+ }
+
+ private initializeConnectorsStatus (): void {
+ if (this.chargingStation.hasEvses) {
+ for (const [evseId, evseStatus] of this.chargingStation.evses) {
+ if (evseId > 0) {
+ for (const connectorId of evseStatus.connectors.keys()) {
+ this.connectorsStatus.set(connectorId, this.getConnectorStatus(connectorId))
+ }
+ }
+ }
+ } else {
+ for (const connectorId of this.chargingStation.connectors.keys()) {
+ if (connectorId > 0) {
+ this.connectorsStatus.set(connectorId, this.getConnectorStatus(connectorId))
+ }
+ }
+ }
+ }
+
+ private getConnectorStatus (connectorId: number): Status {
+ const connectorStatus =
+ this.chargingStation.getAutomaticTransactionGeneratorStatuses()?.[connectorId - 1] != null
+ ? cloneObject<Status>(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.chargingStation.getAutomaticTransactionGeneratorStatuses()![connectorId - 1]
+ )
+ : undefined
+ this.resetConnectorStatus(connectorStatus)
+ return (
+ connectorStatus ?? {
+ start: false,
+ authorizeRequests: 0,
+ acceptedAuthorizeRequests: 0,
+ rejectedAuthorizeRequests: 0,
+ startTransactionRequests: 0,
+ acceptedStartTransactionRequests: 0,
+ rejectedStartTransactionRequests: 0,
+ stopTransactionRequests: 0,
+ acceptedStopTransactionRequests: 0,
+ rejectedStopTransactionRequests: 0,
+ skippedConsecutiveTransactions: 0,
+ skippedTransactions: 0