Prepare code for strict type checking
[e-mobility-charging-stations-simulator.git] / src / charging-station / AutomaticTransactionGenerator.ts
CommitLineData
c0560973 1import { AuthorizationStatus, AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/ocpp/Transaction';
6af9012e
JB
2import { PerformanceObserver, performance } from 'perf_hooks';
3
4import ChargingStation from './ChargingStation';
5import Constants from '../utils/Constants';
6import Utils from '../utils/Utils';
7import logger from '../utils/Logger';
8
9export default class AutomaticTransactionGenerator {
ad2f27c3
JB
10 public timeToStop: boolean;
11 private chargingStation: ChargingStation;
6e0964c8 12 private performanceObserver!: PerformanceObserver;
6af9012e
JB
13
14 constructor(chargingStation: ChargingStation) {
ad2f27c3
JB
15 this.chargingStation = chargingStation;
16 this.timeToStop = true;
17 if (this.chargingStation.getEnableStatistics()) {
18 this.performanceObserver = new PerformanceObserver((list) => {
6af9012e 19 const entry = list.getEntries()[0];
54b1efe0 20 this.chargingStation.performanceStatistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
ad2f27c3 21 this.performanceObserver.disconnect();
6af9012e
JB
22 });
23 }
24 }
25
e268356b 26 public async start(): Promise<void> {
ad2f27c3
JB
27 this.timeToStop = false;
28 if (this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours &&
29 this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours > 0) {
71623267 30 // eslint-disable-next-line @typescript-eslint/no-misused-promises
e268356b
JB
31 setTimeout(async (): Promise<void> => {
32 await this.stop();
ad2f27c3 33 }, this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600 * 1000);
6af9012e 34 }
ad2f27c3 35 for (const connector in this.chargingStation.connectors) {
6af9012e 36 if (Utils.convertToInt(connector) > 0) {
e268356b 37 await this.startConnector(Utils.convertToInt(connector));
6af9012e
JB
38 }
39 }
c0560973 40 logger.info(this.logPrefix() + ' ATG started and will stop in ' + Utils.secondsToHHMMSS(this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600));
6af9012e
JB
41 }
42
c0560973
JB
43 public async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
44 logger.info(this.logPrefix() + ' ATG OVER => STOPPING ALL TRANSACTIONS');
ad2f27c3 45 for (const connector in this.chargingStation.connectors) {
c0560973 46 const transactionId = this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionId;
ad2f27c3 47 if (this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) {
c0560973 48 logger.info(this.logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + transactionId.toString());
035742f7
JB
49 await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId),
50 this.chargingStation.getTransactionIdTag(transactionId), reason);
6af9012e
JB
51 }
52 }
ad2f27c3 53 this.timeToStop = true;
6af9012e
JB
54 }
55
a1256107 56 private async startConnector(connectorId: number): Promise<void> {
6af9012e 57 do {
ad2f27c3 58 if (this.timeToStop) {
c0560973 59 logger.error(this.logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made');
17991e8c
JB
60 break;
61 }
c0560973
JB
62 if (!this.chargingStation.isRegistered()) {
63 logger.error(this.logPrefix(connectorId) + ' Entered in transaction loop while the charging station is not registered');
17991e8c
JB
64 break;
65 }
c0560973
JB
66 if (!this.chargingStation.isChargingStationAvailable()) {
67 logger.info(this.logPrefix(connectorId) + ' Entered in transaction loop while the charging station is unavailable');
ab5f4b03
JB
68 await this.stop();
69 break;
70 }
c0560973
JB
71 if (!this.chargingStation.isConnectorAvailable(connectorId)) {
72 logger.info(`${this.logPrefix(connectorId)} Entered in transaction loop while the connector ${connectorId} is unavailable, stop it`);
17991e8c
JB
73 break;
74 }
c0560973
JB
75 if (!this.chargingStation?.ocppRequestService) {
76 logger.info(`${this.logPrefix(connectorId)} Transaction loop waiting for charging station service to be initialized`);
77 do {
a4cc42ea 78 await Utils.sleep(Constants.CHARGING_STATION_ATG_INITIALIZATION_TIME);
c0560973
JB
79 } while (!this.chargingStation?.ocppRequestService);
80 }
ad2f27c3
JB
81 const wait = Utils.getRandomInt(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
82 this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
c0560973 83 logger.info(this.logPrefix(connectorId) + ' wait for ' + Utils.milliSecondsToHHMMSS(wait));
6af9012e 84 await Utils.sleep(wait);
6af9012e
JB
85 const start = Math.random();
86 let skip = 0;
ad2f27c3 87 if (start < this.chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
6af9012e
JB
88 skip = 0;
89 // Start transaction
4faad557 90 let startResponse: StartTransactionResponse | AuthorizeResponse;
ad2f27c3 91 if (this.chargingStation.getEnableStatistics()) {
6af9012e 92 const startTransaction = performance.timerify(this.startTransaction);
ad2f27c3 93 this.performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 94 startResponse = await startTransaction(connectorId, this);
6af9012e 95 } else {
65c5527e 96 startResponse = await this.startTransaction(connectorId, this);
6af9012e 97 }
ef6076c1 98 if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
54b1efe0 99 logger.warn(this.logPrefix(connectorId) + ' transaction rejected');
6af9012e
JB
100 await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME);
101 } else {
102 // Wait until end of transaction
ad2f27c3
JB
103 const waitTrxEnd = Utils.getRandomInt(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
104 this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
c0560973 105 logger.info(this.logPrefix(connectorId) + ' transaction ' + this.chargingStation.getConnector(connectorId).transactionId.toString() + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd));
6af9012e
JB
106 await Utils.sleep(waitTrxEnd);
107 // Stop transaction
ad2f27c3 108 if (this.chargingStation.getConnector(connectorId)?.transactionStarted) {
c0560973 109 logger.info(this.logPrefix(connectorId) + ' stop transaction ' + this.chargingStation.getConnector(connectorId).transactionId.toString());
ad2f27c3 110 if (this.chargingStation.getEnableStatistics()) {
6af9012e 111 const stopTransaction = performance.timerify(this.stopTransaction);
ad2f27c3 112 this.performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 113 await stopTransaction(connectorId, this);
6af9012e 114 } else {
65c5527e 115 await this.stopTransaction(connectorId, this);
6af9012e
JB
116 }
117 }
118 }
119 } else {
120 skip++;
c0560973 121 logger.info(this.logPrefix(connectorId) + ' transaction skipped ' + skip.toString());
6af9012e 122 }
ad2f27c3 123 } while (!this.timeToStop);
c0560973 124 logger.info(this.logPrefix(connectorId) + ' ATG STOPPED on the connector');
6af9012e
JB
125 }
126
65c5527e 127 // eslint-disable-next-line consistent-this
4faad557 128 private async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StartTransactionResponse | AuthorizeResponse> {
ad2f27c3
JB
129 if (self.chargingStation.hasAuthorizedTags()) {
130 const tagId = self.chargingStation.getRandomTagId();
131 if (self.chargingStation.stationInfo.AutomaticTransactionGenerator.requireAuthorize) {
5fdab605 132 // Authorize tagId
c0560973 133 const authorizeResponse = await self.chargingStation.ocppRequestService.sendAuthorize(tagId);
5fdab605 134 if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
c0560973 135 logger.info(self.logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
5fdab605 136 // Start transaction
c0560973 137 return await self.chargingStation.ocppRequestService.sendStartTransaction(connectorId, tagId);
5fdab605 138 }
4faad557 139 return authorizeResponse;
ef6076c1 140 }
c0560973 141 logger.info(self.logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
5fdab605 142 // Start transaction
c0560973 143 return await self.chargingStation.ocppRequestService.sendStartTransaction(connectorId, tagId);
6af9012e 144 }
c0560973
JB
145 logger.info(self.logPrefix(connectorId) + ' start transaction without a tagID');
146 return await self.chargingStation.ocppRequestService.sendStartTransaction(connectorId);
6af9012e
JB
147 }
148
65c5527e 149 // eslint-disable-next-line consistent-this
17991e8c 150 private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StopTransactionResponse> {
c0560973 151 const transactionId = self.chargingStation.getConnector(connectorId).transactionId;
6e0964c8
JB
152 return await self.chargingStation.ocppRequestService.sendStopTransaction(transactionId, self.chargingStation.getTransactionMeterStop(transactionId),
153 self.chargingStation.getTransactionIdTag(transactionId));
c0560973
JB
154 }
155
6e0964c8 156 private logPrefix(connectorId?: number): string {
c0560973 157 if (connectorId) {
54b1efe0 158 return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' | ATG on connector #' + connectorId.toString() + ':');
c0560973 159 }
54b1efe0 160 return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' | ATG:');
6af9012e
JB
161 }
162}