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