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