refactor: cleanup type definition
[e-mobility-charging-stations-simulator.git] / src / charging-station / AutomaticTransactionGenerator.ts
CommitLineData
edd13439 1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
c8eeb62b 2
66a7748d 3import { hoursToMilliseconds, secondsToMilliseconds } from 'date-fns'
be4c6702 4
66a7748d
JB
5import type { ChargingStation } from './ChargingStation.js'
6import { checkChargingStation } from './Helpers.js'
7import { IdTagsCache } from './IdTagsCache.js'
8import { isIdTagAuthorized } from './ocpp/index.js'
9import { BaseError } from '../exception/index.js'
10import { PerformanceStatistics } from '../performance/index.js'
e7aeea18
JB
11import {
12 AuthorizationStatus,
268a74bb 13 RequestCommand,
976d11ec
JB
14 type StartTransactionRequest,
15 type StartTransactionResponse,
268a74bb 16 type Status,
e7aeea18 17 StopTransactionReason,
66a7748d
JB
18 type StopTransactionResponse
19} from '../types/index.js'
9bf0ef23
JB
20import {
21 Constants,
22 cloneObject,
23 formatDurationMilliSeconds,
24 getRandomInteger,
0a1dd746 25 isValidTime,
9bf0ef23
JB
26 logPrefix,
27 logger,
28 secureRandom,
66a7748d
JB
29 sleep
30} from '../utils/index.js'
6af9012e 31
d1ff8599 32export class AutomaticTransactionGenerator {
e7aeea18 33 private static readonly instances: Map<string, AutomaticTransactionGenerator> = new Map<
66a7748d
JB
34 string,
35 AutomaticTransactionGenerator
36 >()
10068088 37
66a7748d
JB
38 public readonly connectorsStatus: Map<number, Status>
39 public started: boolean
40 private starting: boolean
41 private stopping: boolean
42 private readonly chargingStation: ChargingStation
6af9012e 43
66a7748d
JB
44 private constructor (chargingStation: ChargingStation) {
45 this.started = false
46 this.starting = false
47 this.stopping = false
48 this.chargingStation = chargingStation
49 this.connectorsStatus = new Map<number, Status>()
50 this.initializeConnectorsStatus()
6af9012e
JB
51 }
52
66a7748d
JB
53 public static getInstance (
54 chargingStation: ChargingStation
1895299d 55 ): AutomaticTransactionGenerator | undefined {
5199f9fd
JB
56 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
57 if (!AutomaticTransactionGenerator.instances.has(chargingStation.stationInfo!.hashId)) {
e7aeea18 58 AutomaticTransactionGenerator.instances.set(
5199f9fd
JB
59 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
60 chargingStation.stationInfo!.hashId,
66a7748d
JB
61 new AutomaticTransactionGenerator(chargingStation)
62 )
73b9adec 63 }
5199f9fd
JB
64 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
65 return AutomaticTransactionGenerator.instances.get(chargingStation.stationInfo!.hashId)
73b9adec
JB
66 }
67
66a7748d
JB
68 public start (): void {
69 if (!checkChargingStation(this.chargingStation, this.logPrefix())) {
70 return
d1c6c833 71 }
66a7748d
JB
72 if (this.started) {
73 logger.warn(`${this.logPrefix()} is already started`)
74 return
b809adf1 75 }
66a7748d
JB
76 if (this.starting) {
77 logger.warn(`${this.logPrefix()} is already starting`)
78 return
11353865 79 }
66a7748d
JB
80 this.starting = true
81 this.startConnectors()
82 this.started = true
83 this.starting = false
6af9012e
JB
84 }
85
66a7748d
JB
86 public stop (): void {
87 if (!this.started) {
88 logger.warn(`${this.logPrefix()} is already stopped`)
89 return
265e4266 90 }
66a7748d
JB
91 if (this.stopping) {
92 logger.warn(`${this.logPrefix()} is already stopping`)
93 return
11353865 94 }
66a7748d
JB
95 this.stopping = true
96 this.stopConnectors()
97 this.started = false
98 this.stopping = false
6af9012e
JB
99 }
100
66a7748d
JB
101 public startConnector (connectorId: number): void {
102 if (!checkChargingStation(this.chargingStation, this.logPrefix(connectorId))) {
103 return
d1c6c833 104 }
66a7748d
JB
105 if (!this.connectorsStatus.has(connectorId)) {
106 logger.error(`${this.logPrefix(connectorId)} starting on non existing connector`)
107 throw new BaseError(`Connector ${connectorId} does not exist`)
a5e9befc
JB
108 }
109 if (this.connectorsStatus.get(connectorId)?.start === false) {
66a7748d 110 this.internalStartConnector(connectorId).catch(Constants.EMPTY_FUNCTION)
ecb3869d 111 } else if (this.connectorsStatus.get(connectorId)?.start === true) {
66a7748d 112 logger.warn(`${this.logPrefix(connectorId)} is already started on connector`)
a5e9befc
JB
113 }
114 }
115
66a7748d
JB
116 public stopConnector (connectorId: number): void {
117 if (!this.connectorsStatus.has(connectorId)) {
118 logger.error(`${this.logPrefix(connectorId)} stopping on non existing connector`)
119 throw new BaseError(`Connector ${connectorId} does not exist`)
ba7965c4
JB
120 }
121 if (this.connectorsStatus.get(connectorId)?.start === true) {
66a7748d
JB
122 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
123 this.connectorsStatus.get(connectorId)!.start = false
ba7965c4 124 } else if (this.connectorsStatus.get(connectorId)?.start === false) {
66a7748d 125 logger.warn(`${this.logPrefix(connectorId)} is already stopped on connector`)
ba7965c4 126 }
a5e9befc
JB
127 }
128
66a7748d 129 private startConnectors (): void {
e7aeea18 130 if (
5199f9fd 131 this.connectorsStatus.size > 0 &&
e7aeea18
JB
132 this.connectorsStatus.size !== this.chargingStation.getNumberOfConnectors()
133 ) {
66a7748d
JB
134 this.connectorsStatus.clear()
135 this.initializeConnectorsStatus()
54544ef1 136 }
4334db72
JB
137 if (this.chargingStation.hasEvses) {
138 for (const [evseId, evseStatus] of this.chargingStation.evses) {
139 if (evseId > 0) {
140 for (const connectorId of evseStatus.connectors.keys()) {
66a7748d 141 this.startConnector(connectorId)
4334db72
JB
142 }
143 }
144 }
145 } else {
146 for (const connectorId of this.chargingStation.connectors.keys()) {
147 if (connectorId > 0) {
66a7748d 148 this.startConnector(connectorId)
4334db72 149 }
72740232
JB
150 }
151 }
152 }
153
66a7748d 154 private stopConnectors (): void {
4334db72
JB
155 if (this.chargingStation.hasEvses) {
156 for (const [evseId, evseStatus] of this.chargingStation.evses) {
157 if (evseId > 0) {
158 for (const connectorId of evseStatus.connectors.keys()) {
66a7748d 159 this.stopConnector(connectorId)
4334db72
JB
160 }
161 }
162 }
163 } else {
164 for (const connectorId of this.chargingStation.connectors.keys()) {
165 if (connectorId > 0) {
66a7748d 166 this.stopConnector(connectorId)
4334db72 167 }
72740232
JB
168 }
169 }
170 }
171
66a7748d
JB
172 private async internalStartConnector (connectorId: number): Promise<void> {
173 this.setStartConnectorStatus(connectorId)
e7aeea18 174 logger.info(
44eb6026 175 `${this.logPrefix(
66a7748d 176 connectorId
9bf0ef23 177 )} started on connector and will run for ${formatDurationMilliSeconds(
66a7748d 178 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 179 this.connectorsStatus.get(connectorId)!.stopDate!.getTime() -
66a7748d
JB
180 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
181 this.connectorsStatus.get(connectorId)!.startDate!.getTime()
182 )}`
183 )
1895299d 184 while (this.connectorsStatus.get(connectorId)?.start === true) {
66a7748d
JB
185 await this.waitChargingStationAvailable(connectorId)
186 await this.waitConnectorAvailable(connectorId)
0bd926c1 187 if (!this.canStartConnector(connectorId)) {
66a7748d
JB
188 this.stopConnector(connectorId)
189 break
9b4d0c70 190 }
be4c6702 191 const wait = secondsToMilliseconds(
9bf0ef23 192 getRandomInteger(
ac7f79af 193 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
5199f9fd 194 ?.maxDelayBetweenTwoTransactions,
ac7f79af 195 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
5199f9fd 196 ?.minDelayBetweenTwoTransactions
66a7748d
JB
197 )
198 )
199 logger.info(`${this.logPrefix(connectorId)} waiting for ${formatDurationMilliSeconds(wait)}`)
200 await sleep(wait)
201 const start = secureRandom()
ac7f79af
JB
202 if (
203 start <
5199f9fd
JB
204 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
205 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()!.probabilityOfStart
ac7f79af 206 ) {
66a7748d
JB
207 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
208 this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0
6af9012e 209 // Start transaction
66a7748d 210 const startResponse = await this.startTransaction(connectorId)
5199f9fd 211 if (startResponse?.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
6af9012e 212 // Wait until end of transaction
be4c6702 213 const waitTrxEnd = secondsToMilliseconds(
9bf0ef23 214 getRandomInteger(
5199f9fd
JB
215 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.maxDuration,
216 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.minDuration
66a7748d
JB
217 )
218 )
e7aeea18 219 logger.info(
1c9de2b9 220 `${this.logPrefix(
66a7748d 221 connectorId
1c9de2b9 222 )} transaction started with id ${this.chargingStation.getConnectorStatus(connectorId)
66a7748d
JB
223 ?.transactionId} and will stop in ${formatDurationMilliSeconds(waitTrxEnd)}`
224 )
225 await sleep(waitTrxEnd)
226 await this.stopTransaction(connectorId)
6af9012e
JB
227 }
228 } else {
66a7748d 229 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 230 ++this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions
66a7748d 231 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 232 ++this.connectorsStatus.get(connectorId)!.skippedTransactions
e7aeea18 233 logger.info(
1c9de2b9 234 `${this.logPrefix(connectorId)} skipped consecutively ${this.connectorsStatus.get(
66a7748d 235 connectorId
1c9de2b9 236 )?.skippedConsecutiveTransactions}/${this.connectorsStatus.get(connectorId)
66a7748d
JB
237 ?.skippedTransactions} transaction(s)`
238 )
6af9012e 239 }
66a7748d
JB
240 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
241 this.connectorsStatus.get(connectorId)!.lastRunDate = new Date()
7d75bee1 242 }
66a7748d
JB
243 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
244 this.connectorsStatus.get(connectorId)!.stoppedDate = new Date()
e7aeea18 245 logger.info(
44eb6026 246 `${this.logPrefix(
66a7748d 247 connectorId
9bf0ef23 248 )} stopped on connector and lasted for ${formatDurationMilliSeconds(
66a7748d 249 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 250 this.connectorsStatus.get(connectorId)!.stoppedDate!.getTime() -
66a7748d
JB
251 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
252 this.connectorsStatus.get(connectorId)!.startDate!.getTime()
253 )}`
254 )
e7aeea18 255 logger.debug(
be9ee554 256 `${this.logPrefix(connectorId)} connector status: %j`,
66a7748d
JB
257 this.connectorsStatus.get(connectorId)
258 )
6af9012e
JB
259 }
260
66a7748d 261 private setStartConnectorStatus (connectorId: number): void {
e7aeea18 262 const previousRunDuration =
0a1dd746
JB
263 isValidTime(this.connectorsStatus.get(connectorId)?.startDate) &&
264 isValidTime(this.connectorsStatus.get(connectorId)?.lastRunDate)
66a7748d
JB
265 ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
266 this.connectorsStatus.get(connectorId)!.lastRunDate!.getTime() -
267 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 268 this.connectorsStatus.get(connectorId)!.startDate!.getTime()
66a7748d
JB
269 : 0
270 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
271 this.connectorsStatus.get(connectorId)!.startDate = new Date()
272 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 273 this.connectorsStatus.get(connectorId)!.stopDate = new Date(
66a7748d 274 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
e1d9a0f4 275 this.connectorsStatus.get(connectorId)!.startDate!.getTime() +
be4c6702 276 hoursToMilliseconds(
5199f9fd
JB
277 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
278 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()!.stopAfterHours
be4c6702 279 ) -
66a7748d
JB
280 previousRunDuration
281 )
0a1dd746
JB
282 delete this.connectorsStatus.get(connectorId)?.stoppedDate
283 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
284 this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0
66a7748d
JB
285 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
286 this.connectorsStatus.get(connectorId)!.start = true
4dff3039
JB
287 }
288
66a7748d
JB
289 private canStartConnector (connectorId: number): boolean {
290 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0bd926c1 291 if (new Date() > this.connectorsStatus.get(connectorId)!.stopDate!) {
0a1dd746
JB
292 logger.info(
293 `${this.logPrefix(
294 connectorId
295 )} entered in transaction loop while the ATG stop date has been reached`
296 )
66a7748d 297 return false
0bd926c1 298 }
66a7748d 299 if (!this.chargingStation.inAcceptedState()) {
0bd926c1
JB
300 logger.error(
301 `${this.logPrefix(
66a7748d
JB
302 connectorId
303 )} entered in transaction loop while the charging station is not in accepted state`
304 )
305 return false
0bd926c1 306 }
66a7748d 307 if (!this.chargingStation.isChargingStationAvailable()) {
0bd926c1
JB
308 logger.info(
309 `${this.logPrefix(
66a7748d
JB
310 connectorId
311 )} entered in transaction loop while the charging station is unavailable`
312 )
313 return false
0bd926c1 314 }
66a7748d 315 if (!this.chargingStation.isConnectorAvailable(connectorId)) {
0bd926c1
JB
316 logger.info(
317 `${this.logPrefix(
66a7748d
JB
318 connectorId
319 )} entered in transaction loop while the connector ${connectorId} is unavailable`
320 )
321 return false
0bd926c1 322 }
66a7748d 323 return true
0bd926c1
JB
324 }
325
66a7748d
JB
326 private async waitChargingStationAvailable (connectorId: number): Promise<void> {
327 let logged = false
60400e23
JB
328 while (!this.chargingStation.isChargingStationAvailable()) {
329 if (!logged) {
330 logger.info(
331 `${this.logPrefix(
66a7748d
JB
332 connectorId
333 )} transaction loop waiting for charging station to be available`
334 )
335 logged = true
60400e23 336 }
66a7748d 337 await sleep(Constants.CHARGING_STATION_ATG_AVAILABILITY_TIME)
3e888c65
JB
338 }
339 }
340
66a7748d
JB
341 private async waitConnectorAvailable (connectorId: number): Promise<void> {
342 let logged = false
60400e23
JB
343 while (!this.chargingStation.isConnectorAvailable(connectorId)) {
344 if (!logged) {
345 logger.info(
346 `${this.logPrefix(
66a7748d
JB
347 connectorId
348 )} transaction loop waiting for connector ${connectorId} to be available`
349 )
350 logged = true
60400e23 351 }
66a7748d 352 await sleep(Constants.CHARGING_STATION_ATG_AVAILABILITY_TIME)
3e888c65
JB
353 }
354 }
355
66a7748d 356 private initializeConnectorsStatus (): void {
4334db72
JB
357 if (this.chargingStation.hasEvses) {
358 for (const [evseId, evseStatus] of this.chargingStation.evses) {
359 if (evseId > 0) {
360 for (const connectorId of evseStatus.connectors.keys()) {
66a7748d 361 this.connectorsStatus.set(connectorId, this.getConnectorStatus(connectorId))
4334db72
JB
362 }
363 }
364 }
365 } else {
366 for (const connectorId of this.chargingStation.connectors.keys()) {
367 if (connectorId > 0) {
66a7748d 368 this.connectorsStatus.set(connectorId, this.getConnectorStatus(connectorId))
4334db72 369 }
4dff3039
JB
370 }
371 }
72740232
JB
372 }
373
66a7748d
JB
374 private getConnectorStatus (connectorId: number): Status {
375 const connectorStatus =
0a1dd746 376 this.chargingStation.getAutomaticTransactionGeneratorStatuses()?.[connectorId - 1] != null
66a7748d
JB
377 ? cloneObject<Status>(
378 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 379 this.chargingStation.getAutomaticTransactionGeneratorStatuses()![connectorId - 1]
a82d0329 380 )
66a7748d
JB
381 : undefined
382 this.resetConnectorStatus(connectorStatus)
5ced7e80
JB
383 return (
384 connectorStatus ?? {
385 start: false,
386 authorizeRequests: 0,
387 acceptedAuthorizeRequests: 0,
388 rejectedAuthorizeRequests: 0,
389 startTransactionRequests: 0,
390 acceptedStartTransactionRequests: 0,
391 rejectedStartTransactionRequests: 0,
392 stopTransactionRequests: 0,
393 acceptedStopTransactionRequests: 0,
394 rejectedStopTransactionRequests: 0,
395 skippedConsecutiveTransactions: 0,
66a7748d 396 skippedTransactions: 0
5ced7e80 397 }
66a7748d 398 )
5ced7e80
JB
399 }
400
66a7748d 401 private resetConnectorStatus (connectorStatus: Status | undefined): void {
a807045b 402 if (connectorStatus == null) {
66a7748d 403 return
37e207d1 404 }
3d20f4db
JB
405 if (
406 !this.started &&
66a7748d 407 (connectorStatus.start ||
5199f9fd 408 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.enable !== true)
3d20f4db 409 ) {
66a7748d 410 connectorStatus.start = false
3d20f4db
JB
411 }
412 }
413
66a7748d
JB
414 private async startTransaction (
415 connectorId: number
0afed85f 416 ): Promise<StartTransactionResponse | undefined> {
66a7748d
JB
417 const measureId = 'StartTransaction with ATG'
418 const beginId = PerformanceStatistics.beginMeasure(measureId)
419 let startResponse: StartTransactionResponse | undefined
f911a4af
JB
420 if (this.chargingStation.hasIdTags()) {
421 const idTag = IdTagsCache.getInstance().getIdTag(
66a7748d 422 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
5199f9fd 423 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()!.idTagDistribution!,
aaf2bf9c 424 this.chargingStation,
66a7748d
JB
425 connectorId
426 )
5cf9050d 427 const startTransactionLogMsg = `${this.logPrefix(
66a7748d
JB
428 connectorId
429 )} start transaction with an idTag '${idTag}'`
ccb1d6e9 430 if (this.getRequireAuthorize()) {
66a7748d 431 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 432 ++this.connectorsStatus.get(connectorId)!.authorizeRequests
041365be 433 if (await isIdTagAuthorized(this.chargingStation, connectorId, idTag)) {
66a7748d 434 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 435 ++this.connectorsStatus.get(connectorId)!.acceptedAuthorizeRequests
66a7748d 436 logger.info(startTransactionLogMsg)
5fdab605 437 // Start transaction
f7f98c68 438 startResponse = await this.chargingStation.ocppRequestService.requestHandler<
66a7748d
JB
439 StartTransactionRequest,
440 StartTransactionResponse
08f130a0 441 >(this.chargingStation, RequestCommand.START_TRANSACTION, {
ef6fa3fb 442 connectorId,
66a7748d
JB
443 idTag
444 })
445 this.handleStartTransactionResponse(connectorId, startResponse)
446 PerformanceStatistics.endMeasure(measureId, beginId)
447 return startResponse
5fdab605 448 }
66a7748d 449 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 450 ++this.connectorsStatus.get(connectorId)!.rejectedAuthorizeRequests
66a7748d
JB
451 PerformanceStatistics.endMeasure(measureId, beginId)
452 return startResponse
ef6076c1 453 }
66a7748d 454 logger.info(startTransactionLogMsg)
5fdab605 455 // Start transaction
f7f98c68 456 startResponse = await this.chargingStation.ocppRequestService.requestHandler<
66a7748d
JB
457 StartTransactionRequest,
458 StartTransactionResponse
08f130a0 459 >(this.chargingStation, RequestCommand.START_TRANSACTION, {
ef6fa3fb 460 connectorId,
66a7748d
JB
461 idTag
462 })
463 this.handleStartTransactionResponse(connectorId, startResponse)
464 PerformanceStatistics.endMeasure(measureId, beginId)
465 return startResponse
6af9012e 466 }
66a7748d 467 logger.info(`${this.logPrefix(connectorId)} start transaction without an idTag`)
f7f98c68 468 startResponse = await this.chargingStation.ocppRequestService.requestHandler<
66a7748d
JB
469 StartTransactionRequest,
470 StartTransactionResponse
471 >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId })
472 this.handleStartTransactionResponse(connectorId, startResponse)
473 PerformanceStatistics.endMeasure(measureId, beginId)
474 return startResponse
6af9012e
JB
475 }
476
66a7748d 477 private async stopTransaction (
e7aeea18 478 connectorId: number,
66a7748d 479 reason = StopTransactionReason.LOCAL
e1d9a0f4 480 ): Promise<StopTransactionResponse | undefined> {
66a7748d
JB
481 const measureId = 'StopTransaction with ATG'
482 const beginId = PerformanceStatistics.beginMeasure(measureId)
483 let stopResponse: StopTransactionResponse | undefined
6d9876e7 484 if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
49563992
JB
485 logger.info(
486 `${this.logPrefix(
66a7748d 487 connectorId
49563992 488 )} stop transaction with id ${this.chargingStation.getConnectorStatus(connectorId)
66a7748d
JB
489 ?.transactionId}`
490 )
491 stopResponse = await this.chargingStation.stopTransactionOnConnector(connectorId, reason)
492 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 493 ++this.connectorsStatus.get(connectorId)!.stopTransactionRequests
5199f9fd 494 if (stopResponse.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
66a7748d 495 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 496 ++this.connectorsStatus.get(connectorId)!.acceptedStopTransactionRequests
6d9876e7 497 } else {
66a7748d 498 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 499 ++this.connectorsStatus.get(connectorId)!.rejectedStopTransactionRequests
6d9876e7 500 }
0045cef5 501 } else {
66a7748d 502 const transactionId = this.chargingStation.getConnectorStatus(connectorId)?.transactionId
ff581359 503 logger.debug(
ba7965c4 504 `${this.logPrefix(connectorId)} stopping a not started transaction${
401fa922 505 transactionId != null ? ` with id ${transactionId}` : ''
66a7748d
JB
506 }`
507 )
0045cef5 508 }
66a7748d
JB
509 PerformanceStatistics.endMeasure(measureId, beginId)
510 return stopResponse
c0560973
JB
511 }
512
66a7748d 513 private getRequireAuthorize (): boolean {
ac7f79af
JB
514 return (
515 this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.requireAuthorize ?? true
66a7748d 516 )
ccb1d6e9
JB
517 }
518
66a7748d 519 private readonly logPrefix = (connectorId?: number): string => {
9bf0ef23 520 return logPrefix(
5199f9fd 521 ` ${this.chargingStation.stationInfo?.chargingStationId} | ATG${
401fa922 522 connectorId != null ? ` on connector #${connectorId}` : ''
66a7748d
JB
523 }:`
524 )
525 }
d9ac47ef 526
66a7748d 527 private handleStartTransactionResponse (
d9ac47ef 528 connectorId: number,
66a7748d 529 startResponse: StartTransactionResponse
d9ac47ef 530 ): void {
66a7748d 531 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 532 ++this.connectorsStatus.get(connectorId)!.startTransactionRequests
5199f9fd 533 if (startResponse.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
66a7748d 534 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 535 ++this.connectorsStatus.get(connectorId)!.acceptedStartTransactionRequests
d9ac47ef 536 } else {
66a7748d
JB
537 logger.warn(`${this.logPrefix(connectorId)} start transaction rejected`)
538 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0a1dd746 539 ++this.connectorsStatus.get(connectorId)!.rejectedStartTransactionRequests
d9ac47ef
JB
540 }
541 }
6af9012e 542}