Add logs rotation.
[e-mobility-charging-stations-simulator.git] / src / charging-station / AutomaticTransactionGenerator.ts
1 import { AuthorizationStatus, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/Transaction';
2 import { PerformanceObserver, performance } from 'perf_hooks';
3
4 import ChargingStation from './ChargingStation';
5 import Constants from '../utils/Constants';
6 import Utils from '../utils/Utils';
7 import logger from '../utils/Logger';
8
9 export default class AutomaticTransactionGenerator {
10 private _chargingStation: ChargingStation;
11 private _timeToStop: boolean;
12 private _performanceObserver: PerformanceObserver;
13
14 constructor(chargingStation: ChargingStation) {
15 this._chargingStation = chargingStation;
16 this._timeToStop = true;
17 if (this._chargingStation.getEnableStatistics()) {
18 this._performanceObserver = new PerformanceObserver((list) => {
19 const entry = list.getEntries()[0];
20 this._chargingStation.statistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
21 this._performanceObserver.disconnect();
22 });
23 }
24 }
25
26 get timeToStop(): boolean {
27 return this._timeToStop;
28 }
29
30 _logPrefix(connectorId: number = null): string {
31 if (connectorId) {
32 return Utils.logPrefix(' ' + this._chargingStation.stationInfo.name + ' ATG on connector #' + connectorId.toString() + ':');
33 }
34 return Utils.logPrefix(' ' + this._chargingStation.stationInfo.name + ' ATG:');
35 }
36
37 start(): void {
38 this._timeToStop = false;
39 if (this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours &&
40 this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours > 0) {
41 setTimeout(() => {
42 this.stop();
43 }, this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600 * 1000);
44 }
45 for (const connector in this._chargingStation.connectors) {
46 if (Utils.convertToInt(connector) > 0) {
47 this.startConnector(Utils.convertToInt(connector));
48 }
49 }
50 logger.info(this._logPrefix() + ' ATG started and will stop in ' + Utils.secondsToHHMMSS(this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600));
51 }
52
53 async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
54 logger.info(this._logPrefix() + ' ATG OVER => STOPPING ALL TRANSACTIONS');
55 for (const connector in this._chargingStation.connectors) {
56 if (this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) {
57 logger.info(this._logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId.toString());
58 await this._chargingStation.sendStopTransaction(this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId, reason);
59 }
60 }
61 this._timeToStop = true;
62 }
63
64 async startConnector(connectorId: number): Promise<void> {
65 do {
66 const wait = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
67 this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
68 logger.info(this._logPrefix(connectorId) + ' wait for ' + Utils.milliSecondsToHHMMSS(wait));
69 await Utils.sleep(wait);
70 if (this._timeToStop) {
71 logger.debug(this._logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made');
72 break;
73 }
74 const start = Math.random();
75 let skip = 0;
76 if (start < this._chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
77 skip = 0;
78 // Start transaction
79 let startResponse: StartTransactionResponse;
80 if (this._chargingStation.getEnableStatistics()) {
81 const startTransaction = performance.timerify(this.startTransaction);
82 this._performanceObserver.observe({ entryTypes: ['function'] });
83 startResponse = await startTransaction(connectorId, this);
84 } else {
85 startResponse = await this.startTransaction(connectorId, this);
86 }
87 if (startResponse.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
88 logger.info(this._logPrefix(connectorId) + ' transaction rejected');
89 await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME);
90 } else {
91 // Wait until end of transaction
92 const waitTrxEnd = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
93 this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
94 logger.info(this._logPrefix(connectorId) + ' transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString() + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd));
95 await Utils.sleep(waitTrxEnd);
96 // Stop transaction
97 if (this._chargingStation.getConnector(connectorId).transactionStarted) {
98 logger.info(this._logPrefix(connectorId) + ' stop transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString());
99 if (this._chargingStation.getEnableStatistics()) {
100 const stopTransaction = performance.timerify(this.stopTransaction);
101 this._performanceObserver.observe({ entryTypes: ['function'] });
102 await stopTransaction(connectorId, this);
103 } else {
104 await this.stopTransaction(connectorId, this);
105 }
106 }
107 }
108 } else {
109 skip++;
110 logger.info(this._logPrefix(connectorId) + ' transaction skipped ' + skip.toString());
111 }
112 } while (!this._timeToStop);
113 logger.info(this._logPrefix(connectorId) + ' ATG STOPPED on the connector');
114 }
115
116 // eslint-disable-next-line consistent-this
117 async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StartTransactionResponse> {
118 if (self._chargingStation.hasAuthorizedTags()) {
119 const tagId = self._chargingStation.getRandomTagId();
120 logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
121 return await self._chargingStation.sendStartTransaction(connectorId, tagId);
122 }
123 logger.info(self._logPrefix(connectorId) + ' start transaction without a tagID');
124 return await self._chargingStation.sendStartTransaction(connectorId);
125 }
126
127 // eslint-disable-next-line consistent-this
128 async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StopTransactionResponse> {
129 return await self._chargingStation.sendStopTransaction(self._chargingStation.getConnector(connectorId).transactionId);
130 }
131 }