Add proper worker set elements reference counting.
[e-mobility-charging-stations-simulator.git] / src / charging-station / AutomaticTransactionGenerator.ts
CommitLineData
4faad557 1import { AuthorizationStatus, AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/ocpp/1.6/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;
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];
ad2f27c3
JB
20 this.chargingStation.statistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
21 this.performanceObserver.disconnect();
6af9012e
JB
22 });
23 }
24 }
25
6af9012e
JB
26 _logPrefix(connectorId: number = null): string {
27 if (connectorId) {
ad2f27c3 28 return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG on connector #' + connectorId.toString() + ':');
6af9012e 29 }
ad2f27c3 30 return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' ATG:');
6af9012e
JB
31 }
32
33 start(): void {
ad2f27c3
JB
34 this.timeToStop = false;
35 if (this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours &&
36 this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours > 0) {
6af9012e 37 setTimeout(() => {
ab5f4b03 38 void this.stop();
ad2f27c3 39 }, this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600 * 1000);
6af9012e 40 }
ad2f27c3 41 for (const connector in this.chargingStation.connectors) {
6af9012e 42 if (Utils.convertToInt(connector) > 0) {
ab5f4b03 43 void this.startConnector(Utils.convertToInt(connector));
6af9012e
JB
44 }
45 }
ad2f27c3 46 logger.info(this._logPrefix() + ' ATG started and will stop in ' + Utils.secondsToHHMMSS(this.chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600));
6af9012e
JB
47 }
48
9ac86a7e 49 async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
6af9012e 50 logger.info(this._logPrefix() + ' ATG OVER => STOPPING ALL TRANSACTIONS');
ad2f27c3
JB
51 for (const connector in this.chargingStation.connectors) {
52 if (this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) {
53 logger.info(this._logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionId.toString());
54 await this.chargingStation.sendStopTransaction(this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionId, reason);
6af9012e
JB
55 }
56 }
ad2f27c3 57 this.timeToStop = true;
6af9012e
JB
58 }
59
60 async startConnector(connectorId: number): Promise<void> {
61 do {
ad2f27c3 62 if (this.timeToStop) {
17991e8c
JB
63 logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made');
64 break;
65 }
ad2f27c3 66 if (!this.chargingStation._isRegistered()) {
17991e8c
JB
67 logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station is not registered');
68 break;
69 }
ad2f27c3 70 if (!this.chargingStation._isChargingStationAvailable()) {
ab5f4b03
JB
71 logger.info(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station is unavailable');
72 await this.stop();
73 break;
74 }
ad2f27c3 75 if (!this.chargingStation._isConnectorAvailable(connectorId)) {
ab5f4b03 76 logger.info(`${this._logPrefix(connectorId)} Entered in transaction loop while the connector ${connectorId} is unavailable, stop it`);
17991e8c
JB
77 break;
78 }
ad2f27c3
JB
79 const wait = Utils.getRandomInt(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
80 this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
9ac86a7e 81 logger.info(this._logPrefix(connectorId) + ' wait for ' + Utils.milliSecondsToHHMMSS(wait));
6af9012e 82 await Utils.sleep(wait);
6af9012e
JB
83 const start = Math.random();
84 let skip = 0;
ad2f27c3 85 if (start < this.chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
6af9012e
JB
86 skip = 0;
87 // Start transaction
4faad557 88 let startResponse: StartTransactionResponse | AuthorizeResponse;
ad2f27c3 89 if (this.chargingStation.getEnableStatistics()) {
6af9012e 90 const startTransaction = performance.timerify(this.startTransaction);
ad2f27c3 91 this.performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 92 startResponse = await startTransaction(connectorId, this);
6af9012e 93 } else {
65c5527e 94 startResponse = await this.startTransaction(connectorId, this);
6af9012e 95 }
ef6076c1 96 if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
6af9012e
JB
97 logger.info(this._logPrefix(connectorId) + ' transaction rejected');
98 await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME);
99 } else {
100 // Wait until end of transaction
ad2f27c3
JB
101 const waitTrxEnd = Utils.getRandomInt(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
102 this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
103 logger.info(this._logPrefix(connectorId) + ' transaction ' + this.chargingStation.getConnector(connectorId).transactionId.toString() + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd));
6af9012e
JB
104 await Utils.sleep(waitTrxEnd);
105 // Stop transaction
ad2f27c3
JB
106 if (this.chargingStation.getConnector(connectorId)?.transactionStarted) {
107 logger.info(this._logPrefix(connectorId) + ' stop transaction ' + this.chargingStation.getConnector(connectorId).transactionId.toString());
108 if (this.chargingStation.getEnableStatistics()) {
6af9012e 109 const stopTransaction = performance.timerify(this.stopTransaction);
ad2f27c3 110 this.performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 111 await stopTransaction(connectorId, this);
6af9012e 112 } else {
65c5527e 113 await this.stopTransaction(connectorId, this);
6af9012e
JB
114 }
115 }
116 }
117 } else {
118 skip++;
65c5527e 119 logger.info(this._logPrefix(connectorId) + ' transaction skipped ' + skip.toString());
6af9012e 120 }
ad2f27c3 121 } while (!this.timeToStop);
6af9012e
JB
122 logger.info(this._logPrefix(connectorId) + ' ATG STOPPED on the connector');
123 }
124
65c5527e 125 // eslint-disable-next-line consistent-this
4faad557 126 private async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StartTransactionResponse | AuthorizeResponse> {
ad2f27c3
JB
127 if (self.chargingStation.hasAuthorizedTags()) {
128 const tagId = self.chargingStation.getRandomTagId();
129 if (self.chargingStation.stationInfo.AutomaticTransactionGenerator.requireAuthorize) {
5fdab605 130 // Authorize tagId
ad2f27c3 131 const authorizeResponse = await self.chargingStation.sendAuthorize(tagId);
5fdab605
JB
132 if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
133 logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
134 // Start transaction
ad2f27c3 135 return await self.chargingStation.sendStartTransaction(connectorId, tagId);
5fdab605 136 }
4faad557 137 return authorizeResponse;
ef6076c1 138 }
5fdab605
JB
139 logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
140 // Start transaction
ad2f27c3 141 return await self.chargingStation.sendStartTransaction(connectorId, tagId);
6af9012e 142 }
65c5527e 143 logger.info(self._logPrefix(connectorId) + ' start transaction without a tagID');
ad2f27c3 144 return await self.chargingStation.sendStartTransaction(connectorId);
6af9012e
JB
145 }
146
65c5527e 147 // eslint-disable-next-line consistent-this
17991e8c 148 private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StopTransactionResponse> {
ad2f27c3 149 return await self.chargingStation.sendStopTransaction(self.chargingStation.getConnector(connectorId).transactionId);
6af9012e
JB
150 }
151}