Rename ChargingStationInfo.name -> ChargingStationInfo.chargingStationId
[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 {
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];
10570d97 20 this._chargingStation.statistics.logPerformance(entry, Constants.ENTITY_AUTOMATIC_TRANSACTION_GENERATOR);
6af9012e
JB
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) {
36a16ec2 32 return Utils.logPrefix(' ' + this._chargingStation.stationInfo.chargingStationId + ' ATG on connector #' + connectorId.toString() + ':');
6af9012e 33 }
36a16ec2 34 return Utils.logPrefix(' ' + this._chargingStation.stationInfo.chargingStationId + ' ATG:');
6af9012e
JB
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(() => {
ab5f4b03 42 void this.stop();
6af9012e
JB
43 }, this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600 * 1000);
44 }
45 for (const connector in this._chargingStation.connectors) {
46 if (Utils.convertToInt(connector) > 0) {
ab5f4b03 47 void this.startConnector(Utils.convertToInt(connector));
6af9012e
JB
48 }
49 }
9ac86a7e 50 logger.info(this._logPrefix() + ' ATG started and will stop in ' + Utils.secondsToHHMMSS(this._chargingStation.stationInfo.AutomaticTransactionGenerator.stopAfterHours * 3600));
6af9012e
JB
51 }
52
9ac86a7e 53 async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
6af9012e
JB
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) {
7ec46a9a 57 logger.info(this._logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId.toString());
6af9012e
JB
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 {
17991e8c
JB
66 if (this._timeToStop) {
67 logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made');
68 break;
69 }
70 if (!this._chargingStation._isRegistered()) {
71 logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station is not registered');
72 break;
73 }
ab5f4b03
JB
74 if (!this._chargingStation._isChargingStationAvailable()) {
75 logger.info(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station is unavailable');
76 await this.stop();
77 break;
78 }
79 if (!this._chargingStation._isConnectorAvailable(connectorId)) {
80 logger.info(`${this._logPrefix(connectorId)} Entered in transaction loop while the connector ${connectorId} is unavailable, stop it`);
17991e8c
JB
81 break;
82 }
6af9012e
JB
83 const wait = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
84 this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
9ac86a7e 85 logger.info(this._logPrefix(connectorId) + ' wait for ' + Utils.milliSecondsToHHMMSS(wait));
6af9012e 86 await Utils.sleep(wait);
6af9012e
JB
87 const start = Math.random();
88 let skip = 0;
89 if (start < this._chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
90 skip = 0;
91 // Start transaction
4faad557 92 let startResponse: StartTransactionResponse | AuthorizeResponse;
6af9012e
JB
93 if (this._chargingStation.getEnableStatistics()) {
94 const startTransaction = performance.timerify(this.startTransaction);
95 this._performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 96 startResponse = await startTransaction(connectorId, this);
6af9012e 97 } else {
65c5527e 98 startResponse = await this.startTransaction(connectorId, this);
6af9012e 99 }
ef6076c1 100 if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
6af9012e
JB
101 logger.info(this._logPrefix(connectorId) + ' transaction rejected');
102 await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME);
103 } else {
104 // Wait until end of transaction
105 const waitTrxEnd = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
106 this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
7ec46a9a 107 logger.info(this._logPrefix(connectorId) + ' transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString() + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd));
6af9012e
JB
108 await Utils.sleep(waitTrxEnd);
109 // Stop transaction
4dff73b0 110 if (this._chargingStation.getConnector(connectorId)?.transactionStarted) {
7ec46a9a 111 logger.info(this._logPrefix(connectorId) + ' stop transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString());
6af9012e
JB
112 if (this._chargingStation.getEnableStatistics()) {
113 const stopTransaction = performance.timerify(this.stopTransaction);
114 this._performanceObserver.observe({ entryTypes: ['function'] });
65c5527e 115 await stopTransaction(connectorId, this);
6af9012e 116 } else {
65c5527e 117 await this.stopTransaction(connectorId, this);
6af9012e
JB
118 }
119 }
120 }
121 } else {
122 skip++;
65c5527e 123 logger.info(this._logPrefix(connectorId) + ' transaction skipped ' + skip.toString());
6af9012e
JB
124 }
125 } while (!this._timeToStop);
126 logger.info(this._logPrefix(connectorId) + ' ATG STOPPED on the connector');
127 }
128
65c5527e 129 // eslint-disable-next-line consistent-this
4faad557 130 private async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StartTransactionResponse | AuthorizeResponse> {
65c5527e
JB
131 if (self._chargingStation.hasAuthorizedTags()) {
132 const tagId = self._chargingStation.getRandomTagId();
5fdab605
JB
133 if (self._chargingStation.stationInfo.AutomaticTransactionGenerator.requireAuthorize) {
134 // Authorize tagId
135 const authorizeResponse = await self._chargingStation.sendAuthorize(tagId);
136 if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
137 logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
138 // Start transaction
139 return await self._chargingStation.sendStartTransaction(connectorId, tagId);
140 }
4faad557 141 return authorizeResponse;
ef6076c1 142 }
5fdab605
JB
143 logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
144 // Start transaction
145 return await self._chargingStation.sendStartTransaction(connectorId, tagId);
6af9012e 146 }
65c5527e
JB
147 logger.info(self._logPrefix(connectorId) + ' start transaction without a tagID');
148 return await self._chargingStation.sendStartTransaction(connectorId);
6af9012e
JB
149 }
150
65c5527e 151 // eslint-disable-next-line consistent-this
17991e8c 152 private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StopTransactionResponse> {
9ac86a7e 153 return await self._chargingStation.sendStopTransaction(self._chargingStation.getConnector(connectorId).transactionId);
6af9012e
JB
154 }
155}