1 import { AuthorizationStatus
, AuthorizeResponse
, StartTransactionResponse
, StopTransactionReason
, StopTransactionResponse
} from
'../types/ocpp/Transaction';
3 import ChargingStation from
'./ChargingStation';
4 import Constants from
'../utils/Constants';
5 import PerformanceStatistics from
'../utils/PerformanceStatistics';
6 import Utils from
'../utils/Utils';
7 import logger from
'../utils/Logger';
9 export default class AutomaticTransactionGenerator
{
10 public timeToStop
: boolean;
11 private chargingStation
: ChargingStation
;
13 constructor(chargingStation
: ChargingStation
) {
14 this.chargingStation
= chargingStation
;
15 this.timeToStop
= true;
18 public async start(): Promise
<void> {
19 this.timeToStop
= false;
20 if (this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.stopAfterHours
&&
21 this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.stopAfterHours
> 0) {
22 // eslint-disable-next-line @typescript-eslint/no-misused-promises
23 setTimeout(async (): Promise
<void> => {
25 }, this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.stopAfterHours
* 3600 * 1000);
27 for (const connector
in this.chargingStation
.connectors
) {
28 if (Utils
.convertToInt(connector
) > 0) {
29 await this.startConnector(Utils
.convertToInt(connector
));
32 logger
.info(this.logPrefix() + ' ATG started and will stop in ' + Utils
.secondsToHHMMSS(this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.stopAfterHours
* 3600));
35 public async stop(reason
: StopTransactionReason
= StopTransactionReason
.NONE
): Promise
<void> {
36 logger
.info(this.logPrefix() + ' ATG OVER => STOPPING ALL TRANSACTIONS');
37 for (const connector
in this.chargingStation
.connectors
) {
38 const transactionId
= this.chargingStation
.getConnector(Utils
.convertToInt(connector
)).transactionId
;
39 if (this.chargingStation
.getConnector(Utils
.convertToInt(connector
)).transactionStarted
) {
40 logger
.info(this.logPrefix(Utils
.convertToInt(connector
)) + ' ATG OVER. Stop transaction ' + transactionId
.toString());
41 await this.chargingStation
.ocppRequestService
.sendStopTransaction(transactionId
, this.chargingStation
.getEnergyActiveImportRegisterByTransactionId(transactionId
),
42 this.chargingStation
.getTransactionIdTag(transactionId
), reason
);
45 this.timeToStop
= true;
48 private async startConnector(connectorId
: number): Promise
<void> {
50 if (this.timeToStop
) {
51 logger
.error(this.logPrefix(connectorId
) + ' Entered in transaction loop while a request to stop it was made');
54 if (!this.chargingStation
.isRegistered()) {
55 logger
.error(this.logPrefix(connectorId
) + ' Entered in transaction loop while the charging station is not registered');
58 if (!this.chargingStation
.isChargingStationAvailable()) {
59 logger
.info(this.logPrefix(connectorId
) + ' Entered in transaction loop while the charging station is unavailable');
63 if (!this.chargingStation
.isConnectorAvailable(connectorId
)) {
64 logger
.info(`${this.logPrefix(connectorId)} Entered in transaction loop while the connector ${connectorId} is unavailable, stop it`);
67 if (!this.chargingStation
?.ocppRequestService
) {
68 logger
.info(`${this.logPrefix(connectorId)} Transaction loop waiting for charging station service to be initialized`);
70 await Utils
.sleep(Constants
.CHARGING_STATION_ATG_INITIALIZATION_TIME
);
71 } while (!this.chargingStation
?.ocppRequestService
);
73 const wait
= Utils
.getRandomInt(this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.maxDelayBetweenTwoTransactions
,
74 this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.minDelayBetweenTwoTransactions
) * 1000;
75 logger
.info(this.logPrefix(connectorId
) + ' wait for ' + Utils
.milliSecondsToHHMMSS(wait
));
76 await Utils
.sleep(wait
);
77 const start
= Math.random();
79 if (start
< this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.probabilityOfStart
) {
81 let startATGTransaction
: (connectorId
: number, self: AutomaticTransactionGenerator
) => Promise
<StartTransactionResponse
| AuthorizeResponse
>;
82 if (this.chargingStation
.getEnableStatistics()) {
83 startATGTransaction
= PerformanceStatistics
.timedFunction(this.startATGTransaction
.bind(this));
85 startATGTransaction
= this.startATGTransaction
.bind(this);
87 const startResponse
= await startATGTransaction(connectorId
, this);
88 if (startResponse
?.idTagInfo
?.status !== AuthorizationStatus
.ACCEPTED
) {
89 logger
.warn(this.logPrefix(connectorId
) + ' transaction rejected');
90 await Utils
.sleep(Constants
.CHARGING_STATION_ATG_WAIT_TIME
);
92 // Wait until end of transaction
93 const waitTrxEnd
= Utils
.getRandomInt(this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.maxDuration
,
94 this.chargingStation
.stationInfo
.AutomaticTransactionGenerator
.minDuration
) * 1000;
95 logger
.info(this.logPrefix(connectorId
) + ' transaction ' + this.chargingStation
.getConnector(connectorId
).transactionId
.toString() + ' will stop in ' + Utils
.milliSecondsToHHMMSS(waitTrxEnd
));
96 await Utils
.sleep(waitTrxEnd
);
98 if (this.chargingStation
.getConnector(connectorId
)?.transactionStarted
) {
99 logger
.info(this.logPrefix(connectorId
) + ' stop transaction ' + this.chargingStation
.getConnector(connectorId
).transactionId
.toString());
100 let stopATGTransaction
: (connectorId
: number, self: AutomaticTransactionGenerator
) => Promise
<StopTransactionResponse
>;
101 if (this.chargingStation
.getEnableStatistics()) {
102 stopATGTransaction
= PerformanceStatistics
.timedFunction(this.stopATGTransaction
.bind(this));
104 stopATGTransaction
= this.stopATGTransaction
.bind(this);
106 await stopATGTransaction(connectorId
, this);
111 logger
.info(this.logPrefix(connectorId
) + ' transaction skipped ' + skip
.toString());
113 } while (!this.timeToStop
);
114 logger
.info(this.logPrefix(connectorId
) + ' ATG STOPPED on the connector');
117 // eslint-disable-next-line consistent-this
118 private async startATGTransaction(connectorId
: number, self: AutomaticTransactionGenerator
): Promise
<StartTransactionResponse
| AuthorizeResponse
> {
119 if (self.chargingStation
.hasAuthorizedTags()) {
120 const tagId
= self.chargingStation
.getRandomTagId();
121 if (self.chargingStation
.getAutomaticTransactionGeneratorRequireAuthorize()) {
123 const authorizeResponse
= await self.chargingStation
.ocppRequestService
.sendAuthorize(connectorId
, tagId
);
124 if (authorizeResponse
?.idTagInfo
?.status === AuthorizationStatus
.ACCEPTED
) {
125 logger
.info(self.logPrefix(connectorId
) + ' start transaction for tagID ' + tagId
);
127 return self.chargingStation
.ocppRequestService
.sendStartTransaction(connectorId
, tagId
);
129 return authorizeResponse
;
131 logger
.info(self.logPrefix(connectorId
) + ' start transaction for tagID ' + tagId
);
133 return self.chargingStation
.ocppRequestService
.sendStartTransaction(connectorId
, tagId
);
135 logger
.info(self.logPrefix(connectorId
) + ' start transaction without a tagID');
136 return self.chargingStation
.ocppRequestService
.sendStartTransaction(connectorId
);
139 // eslint-disable-next-line consistent-this
140 private async stopATGTransaction(connectorId
: number, self: AutomaticTransactionGenerator
): Promise
<StopTransactionResponse
> {
141 const transactionId
= self.chargingStation
.getConnector(connectorId
).transactionId
;
142 return self.chargingStation
.ocppRequestService
.sendStopTransaction(transactionId
, self.chargingStation
.getEnergyActiveImportRegisterByTransactionId(transactionId
),
143 self.chargingStation
.getTransactionIdTag(transactionId
));
146 private logPrefix(connectorId
?: number): string {
148 return Utils
.logPrefix(' ' + this.chargingStation
.stationInfo
.chargingStationId
+ ' | ATG on connector #' + connectorId
.toString() + ':');
150 return Utils
.logPrefix(' ' + this.chargingStation
.stationInfo
.chargingStationId
+ ' | ATG:');