- this.startDate = new Date();
- this.stopDate = new Date(this.startDate.getTime()
- + (this.chargingStation.stationInfo?.AutomaticTransactionGenerator?.stopAfterHours ?? Constants.CHARGING_STATION_ATG_DEFAULT_STOP_AFTER_HOURS) * 3600 * 1000
- - (this.runningDuration ?? 0));
- this.timeToStop = false;
- for (const connector in this.chargingStation.connectors) {
- if (Utils.convertToInt(connector) > 0) {
- // Avoid hogging the event loop with a busy loop
- setImmediate(() => {
- this.startOnConnector(Utils.convertToInt(connector)).catch(() => { /* This is intentional */ });
- });
- }
- }
- logger.info(this.logPrefix() + ' started and will run for ' + Utils.formatDurationMilliSeconds(this.stopDate.getTime() - this.startDate.getTime()));
- }
-
- public async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
- logger.info(`${this.logPrefix()} over and lasted for ${Utils.formatDurationMilliSeconds(this.runningDuration ?? 0)}. Stopping all transactions`);
- for (const connector in this.chargingStation.connectors) {
- const transactionId = this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionId;
- if (this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) {
- logger.info(this.logPrefix(Utils.convertToInt(connector)) + ' over. Stop transaction ' + transactionId.toString());
- await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
- this.chargingStation.getTransactionIdTag(transactionId), reason);
- }
- }
- this.timeToStop = true;
- }
-
- private async startOnConnector(connectorId: number): Promise<void> {
- logger.info(this.logPrefix(connectorId) + ' started on connector');
- let transactionSkip = 0;
- let totalTransactionSkip = 0;
- while (!this.timeToStop) {
- if ((new Date()) > this.stopDate) {
- await this.stop();
+ if (checkChargingStation(this.chargingStation, this.logPrefix()) === false) {
+ return;
+ }
+ if (this.started === true) {
+ logger.warn(`${this.logPrefix()} is already started`);
+ return;
+ }
+ if (this.starting === true) {
+ logger.warn(`${this.logPrefix()} is already starting`);
+ return;
+ }
+ this.starting = true;
+ this.startConnectors();
+ this.started = true;
+ this.starting = false;
+ }
+
+ public stop(): void {
+ if (this.started === false) {
+ logger.warn(`${this.logPrefix()} is already stopped`);
+ return;
+ }
+ if (this.stopping === true) {
+ logger.warn(`${this.logPrefix()} is already stopping`);
+ return;
+ }
+ this.stopping = true;
+ this.stopConnectors();
+ this.started = false;
+ this.stopping = false;
+ }
+
+ public startConnector(connectorId: number): void {
+ if (checkChargingStation(this.chargingStation, this.logPrefix(connectorId)) === false) {
+ return;
+ }
+ if (this.connectorsStatus.has(connectorId) === false) {
+ logger.error(`${this.logPrefix(connectorId)} starting on non existing connector`);
+ throw new BaseError(`Connector ${connectorId} does not exist`);
+ }
+ if (this.connectorsStatus.get(connectorId)?.start === false) {
+ this.runInAsyncScope(
+ this.internalStartConnector.bind(this) as (
+ this: AutomaticTransactionGenerator,
+ ...args: unknown[]
+ ) => Promise<void>,
+ this,
+ connectorId,
+ ).catch(Constants.EMPTY_FUNCTION);
+ } else if (this.connectorsStatus.get(connectorId)?.start === true) {
+ logger.warn(`${this.logPrefix(connectorId)} is already started on connector`);
+ }
+ }
+
+ public stopConnector(connectorId: number): void {
+ if (this.connectorsStatus.has(connectorId) === false) {
+ logger.error(`${this.logPrefix(connectorId)} stopping on non existing connector`);
+ throw new BaseError(`Connector ${connectorId} does not exist`);
+ }
+ if (this.connectorsStatus.get(connectorId)?.start === true) {
+ this.connectorsStatus.get(connectorId)!.start = false;
+ } else if (this.connectorsStatus.get(connectorId)?.start === false) {
+ logger.warn(`${this.logPrefix(connectorId)} is already stopped on connector`);
+ }
+ }
+
+ private startConnectors(): void {
+ if (
+ this.connectorsStatus?.size > 0 &&
+ this.connectorsStatus.size !== this.chargingStation.getNumberOfConnectors()
+ ) {
+ this.connectorsStatus.clear();
+ this.initializeConnectorsStatus();
+ }
+ if (this.chargingStation.hasEvses) {
+ for (const [evseId, evseStatus] of this.chargingStation.evses) {
+ if (evseId > 0) {
+ for (const connectorId of evseStatus.connectors.keys()) {
+ this.startConnector(connectorId);
+ }
+ }
+ }
+ } else {
+ for (const connectorId of this.chargingStation.connectors.keys()) {
+ if (connectorId > 0) {
+ this.startConnector(connectorId);
+ }
+ }
+ }
+ }
+
+ private stopConnectors(): void {
+ if (this.chargingStation.hasEvses) {
+ for (const [evseId, evseStatus] of this.chargingStation.evses) {
+ if (evseId > 0) {
+ for (const connectorId of evseStatus.connectors.keys()) {
+ this.stopConnector(connectorId);
+ }
+ }
+ }
+ } else {
+ for (const connectorId of this.chargingStation.connectors.keys()) {
+ if (connectorId > 0) {
+ this.stopConnector(connectorId);
+ }
+ }
+ }
+ }
+
+ private async internalStartConnector(connectorId: number): Promise<void> {
+ this.setStartConnectorStatus(connectorId);
+ logger.info(
+ `${this.logPrefix(
+ connectorId,
+ )} started on connector and will run for ${formatDurationMilliSeconds(
+ this.connectorsStatus.get(connectorId)!.stopDate!.getTime() -
+ this.connectorsStatus.get(connectorId)!.startDate!.getTime(),
+ )}`,
+ );
+ while (this.connectorsStatus.get(connectorId)?.start === true) {
+ if (new Date() > this.connectorsStatus.get(connectorId)!.stopDate!) {
+ this.stopConnector(connectorId);
+ break;
+ }
+ if (this.chargingStation.inAcceptedState() === false) {
+ logger.error(
+ `${this.logPrefix(
+ connectorId,
+ )} entered in transaction loop while the charging station is not in accepted state`,
+ );
+ this.stopConnector(connectorId);