X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=9a8f468b37bee455378b890a2392a4e02a9dfefb;hb=e64c6fa982ba3270bb015deea30eece32b4661de;hp=2456d0d6965175a2a1ce366e4cbb7b25a6c90e28;hpb=a4f7c75ff42b0545400ca0e9ddbbf9b72f32774f;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 2456d0d6..9a8f468b 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -9,31 +9,24 @@ import { parentPort } from 'node:worker_threads'; import merge from 'just-merge'; import WebSocket, { type RawData } from 'ws'; +import { AutomaticTransactionGenerator } from './AutomaticTransactionGenerator'; +import { ChargingStationWorkerBroadcastChannel } from './broadcast-channel/ChargingStationWorkerBroadcastChannel'; +import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; +import { ChargingStationUtils } from './ChargingStationUtils'; +import { IdTagsCache } from './IdTagsCache'; import { - AutomaticTransactionGenerator, - ChargingStationConfigurationUtils, - ChargingStationUtils, - ChargingStationWorkerBroadcastChannel, - IdTagsCache, - MessageChannelUtils, - SharedLRUCache, -} from './internal'; -import { - // OCPP16IncomingRequestService, + OCPP16IncomingRequestService, OCPP16RequestService, - // OCPP16ResponseService, + OCPP16ResponseService, OCPP16ServiceUtils, OCPP20IncomingRequestService, OCPP20RequestService, - // OCPP20ResponseService, + OCPP20ResponseService, type OCPPIncomingRequestService, type OCPPRequestService, - // OCPPServiceUtils, + OCPPServiceUtils, } from './ocpp'; -import { OCPP16IncomingRequestService } from './ocpp/1.6/OCPP16IncomingRequestService'; -import { OCPP16ResponseService } from './ocpp/1.6/OCPP16ResponseService'; -import { OCPP20ResponseService } from './ocpp/2.0/OCPP20ResponseService'; -import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils'; +import { SharedLRUCache } from './SharedLRUCache'; import { BaseError, OCPPError } from '../exception'; import { PerformanceStatistics } from '../performance'; import { @@ -76,6 +69,7 @@ import { RequestCommand, type Response, StandardParametersKey, + type Status, type StatusNotificationRequest, type StatusNotificationResponse, StopTransactionReason, @@ -90,12 +84,21 @@ import { } from '../types'; import { ACElectricUtils, + AsyncLock, + AsyncLockType, Configuration, Constants, DCElectricUtils, - FileUtils, Utils, + buildChargingStationAutomaticTransactionGeneratorConfiguration, + buildConnectorsStatus, + buildEvsesStatus, + buildStartedMessage, + buildStoppedMessage, + buildUpdatedMessage, + handleFileException, logger, + watchJsonFile, } from '../utils'; export class ChargingStation { @@ -108,7 +111,7 @@ export class ChargingStation { public automaticTransactionGenerator!: AutomaticTransactionGenerator | undefined; public ocppConfiguration!: ChargingStationOcppConfiguration | undefined; public wsConnection!: WebSocket | null; - public connectors: Map; + public readonly connectors: Map; public readonly evses: Map; public readonly requests: Map; public performanceStatistics!: PerformanceStatistics | undefined; @@ -160,11 +163,17 @@ export class ChargingStation { return new URL( `${ this.getSupervisionUrlOcppConfiguration() && - Utils.isNotEmptyString(this.getSupervisionUrlOcppKey()) + Utils.isNotEmptyString(this.getSupervisionUrlOcppKey()) && + Utils.isNotEmptyString( + ChargingStationConfigurationUtils.getConfigurationKey( + this, + this.getSupervisionUrlOcppKey() + )?.value + ) ? ChargingStationConfigurationUtils.getConfigurationKey( this, this.getSupervisionUrlOcppKey() - )?.value + ).value : this.configuredSupervisionUrl.href }/${this.stationInfo.chargingStationId}` ); @@ -182,8 +191,9 @@ export class ChargingStation { }; public hasIdTags(): boolean { - const idTagsFile = ChargingStationUtils.getIdTagsFile(this.stationInfo); - return Utils.isNotEmptyArray(this.idTagsCache.getIdTags(idTagsFile)); + return Utils.isNotEmptyArray( + this.idTagsCache.getIdTags(ChargingStationUtils.getIdTagsFile(this.stationInfo)) + ); } public getEnableStatistics(): boolean { @@ -218,26 +228,26 @@ export class ChargingStation { return this?.bootNotificationResponse?.status; } - public isInUnknownState(): boolean { + public inUnknownState(): boolean { return Utils.isNullOrUndefined(this?.bootNotificationResponse?.status); } - public isInPendingState(): boolean { + public inPendingState(): boolean { return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.PENDING; } - public isInAcceptedState(): boolean { + public inAcceptedState(): boolean { return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.ACCEPTED; } - public isInRejectedState(): boolean { + public inRejectedState(): boolean { return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.REJECTED; } public isRegistered(): boolean { return ( - this.isInUnknownState() === false && - (this.isInAcceptedState() === true || this.isInPendingState() === true) + this.inUnknownState() === false && + (this.inAcceptedState() === true || this.inPendingState() === true) ); } @@ -316,10 +326,7 @@ export class ChargingStation { this.logPrefix(), this.templateFile ); - const localStationInfo: ChargingStationInfo = stationInfo ?? this.stationInfo; - return !Utils.isUndefined(localStationInfo.voltageOut) - ? localStationInfo.voltageOut - : defaultVoltageOut; + return (stationInfo ?? this.stationInfo).voltageOut ?? defaultVoltageOut; } public getMaximumPower(stationInfo?: ChargingStationInfo): number { @@ -640,7 +647,7 @@ export class ChargingStation { } this.openWSConnection(); // Monitor charging station template file - this.templateFileWatcher = FileUtils.watchJsonFile( + this.templateFileWatcher = watchJsonFile( this.templateFile, FileType.ChargingStationTemplate, this.logPrefix(), @@ -658,9 +665,7 @@ export class ChargingStation { this.initialize(); // Restart the ATG this.stopAutomaticTransactionGenerator(); - if ( - this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true - ) { + if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) { this.startAutomaticTransactionGenerator(); } if (this.getEnableStatistics() === true) { @@ -679,7 +684,7 @@ export class ChargingStation { } ); this.started = true; - parentPort?.postMessage(MessageChannelUtils.buildStartedMessage(this)); + parentPort?.postMessage(buildStartedMessage(this)); this.starting = false; } else { logger.warn(`${this.logPrefix()} Charging station is already starting...`); @@ -703,7 +708,8 @@ export class ChargingStation { this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash); delete this.bootNotificationResponse; this.started = false; - parentPort?.postMessage(MessageChannelUtils.buildStoppedMessage(this)); + this.saveConfiguration(); + parentPort?.postMessage(buildStoppedMessage(this)); this.stopping = false; } else { logger.warn(`${this.logPrefix()} Charging station is already stopping...`); @@ -744,7 +750,7 @@ export class ChargingStation { terminateOpened: false, } ): void { - options.handshakeTimeout = options?.handshakeTimeout ?? this.getConnectionTimeout() * 1000; + options = { handshakeTimeout: this.getConnectionTimeout() * 1000, ...options }; params = { ...{ closeOpened: false, terminateOpened: false }, ...params }; if (this.started === false && this.starting === false) { logger.warn( @@ -812,15 +818,36 @@ export class ChargingStation { } } - public startAutomaticTransactionGenerator( - connectorIds?: number[], - automaticTransactionGeneratorConfiguration?: AutomaticTransactionGeneratorConfiguration - ): void { - this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance( - automaticTransactionGeneratorConfiguration ?? - this.getAutomaticTransactionGeneratorConfigurationFromTemplate(), - this - ); + public getAutomaticTransactionGeneratorConfiguration(): + | AutomaticTransactionGeneratorConfiguration + | undefined { + let automaticTransactionGeneratorConfiguration: + | AutomaticTransactionGeneratorConfiguration + | undefined; + const automaticTransactionGeneratorConfigurationFromFile = + this.getConfigurationFromFile()?.automaticTransactionGenerator; + if ( + this.getAutomaticTransactionGeneratorPersistentConfiguration() && + automaticTransactionGeneratorConfigurationFromFile + ) { + automaticTransactionGeneratorConfiguration = + automaticTransactionGeneratorConfigurationFromFile; + } else { + automaticTransactionGeneratorConfiguration = + this.getTemplateFromFile()?.AutomaticTransactionGenerator; + } + return { + ...Constants.DEFAULT_ATG_CONFIGURATION, + ...automaticTransactionGeneratorConfiguration, + }; + } + + public getAutomaticTransactionGeneratorStatuses(): Status[] | undefined { + return this.getConfigurationFromFile()?.automaticTransactionGeneratorStatuses; + } + + public startAutomaticTransactionGenerator(connectorIds?: number[]): void { + this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance(this); if (Utils.isNotEmptyArray(connectorIds)) { for (const connectorId of connectorIds) { this.automaticTransactionGenerator?.startConnector(connectorId); @@ -828,7 +855,8 @@ export class ChargingStation { } else { this.automaticTransactionGenerator?.start(); } - parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); + this.saveAutomaticTransactionGeneratorConfiguration(); + parentPort?.postMessage(buildUpdatedMessage(this)); } public stopAutomaticTransactionGenerator(connectorIds?: number[]): void { @@ -839,7 +867,8 @@ export class ChargingStation { } else { this.automaticTransactionGenerator?.stop(); } - parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); + this.saveAutomaticTransactionGeneratorConfiguration(); + parentPort?.postMessage(buildUpdatedMessage(this)); } public async stopTransactionOnConnector( @@ -930,7 +959,7 @@ export class ChargingStation { this.templateFileHash = template.templateHash; } } catch (error) { - FileUtils.handleFileException( + handleFileException( this.templateFile, FileType.ChargingStationTemplate, error as NodeJS.ErrnoException, @@ -942,7 +971,7 @@ export class ChargingStation { private getStationInfoFromTemplate(): ChargingStationInfo { const stationTemplate: ChargingStationTemplate | undefined = this.getTemplateFromFile(); - ChargingStationUtils.checkTemplateFile(stationTemplate, this.logPrefix(), this.templateFile); + ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); ChargingStationUtils.warnTemplateKeysDeprecation( stationTemplate, this.logPrefix(), @@ -1049,6 +1078,10 @@ export class ChargingStation { return this.stationInfo?.stationInfoPersistentConfiguration ?? true; } + private getAutomaticTransactionGeneratorPersistentConfiguration(): boolean { + return this.stationInfo?.automaticTransactionGeneratorPersistentConfiguration ?? true; + } + private handleUnsupportedVersion(version: OCPPVersion) { const errorMsg = `Unsupported protocol version '${version}' configured in template file ${this.templateFile}`; logger.error(`${this.logPrefix()} ${errorMsg}`); @@ -1057,15 +1090,14 @@ export class ChargingStation { private initialize(): void { const stationTemplate = this.getTemplateFromFile(); - ChargingStationUtils.checkTemplateFile(stationTemplate, this.logPrefix(), this.templateFile); + ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); this.configurationFile = path.join( path.dirname(this.templateFile.replace('station-templates', 'configurations')), `${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json` ); const chargingStationConfiguration = this.getConfigurationFromFile(); - const featureFlag = false; if ( - featureFlag && + chargingStationConfiguration?.stationInfo?.templateHash === stationTemplate?.templateHash && (chargingStationConfiguration?.connectorsStatus || chargingStationConfiguration?.evsesStatus) ) { this.initializeConnectorsOrEvsesFromFile(chargingStationConfiguration); @@ -1309,18 +1341,15 @@ export class ChargingStation { private initializeConnectorsOrEvsesFromFile(configuration: ChargingStationConfiguration): void { if (configuration?.connectorsStatus && !configuration?.evsesStatus) { - this.connectors = new Map( - configuration?.connectorsStatus.map((connectorStatus, connectorId) => [ - connectorId, - connectorStatus, - ]) - ); + for (const [connectorId, connectorStatus] of configuration.connectorsStatus.entries()) { + this.connectors.set(connectorId, Utils.cloneObject(connectorStatus)); + } } else if (configuration?.evsesStatus && !configuration?.connectorsStatus) { for (const [evseId, evseStatusConfiguration] of configuration.evsesStatus.entries()) { - const evseStatus = Utils.cloneObject(evseStatusConfiguration); + const evseStatus = Utils.cloneObject(evseStatusConfiguration); delete evseStatus.connectorsStatus; this.evses.set(evseId, { - ...evseStatus, + ...(evseStatus as EvseStatus), connectors: new Map( evseStatusConfiguration.connectorsStatus.map((connectorStatus, connectorId) => [ connectorId, @@ -1451,7 +1480,7 @@ export class ChargingStation { if (stationTemplate?.Evses) { const evsesConfigHash = crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) - .update(`${JSON.stringify(stationTemplate?.Evses)}`) + .update(JSON.stringify(stationTemplate?.Evses)) .digest('hex'); const evsesConfigChanged = this.evses?.size !== 0 && this.evsesConfigurationHash !== evsesConfigHash; @@ -1495,7 +1524,7 @@ export class ChargingStation { private getConfigurationFromFile(): ChargingStationConfiguration | undefined { let configuration: ChargingStationConfiguration | undefined; - if (this.configurationFile && fs.existsSync(this.configurationFile)) { + if (Utils.isNotEmptyString(this.configurationFile) && fs.existsSync(this.configurationFile)) { try { if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) { configuration = this.sharedLRUCache.getChargingStationConfiguration( @@ -1512,7 +1541,7 @@ export class ChargingStation { this.configurationFileHash = configuration.configurationHash; } } catch (error) { - FileUtils.handleFileException( + handleFileException( this.configurationFile, FileType.ChargingStationConfiguration, error as NodeJS.ErrnoException, @@ -1523,6 +1552,12 @@ export class ChargingStation { return configuration; } + private saveAutomaticTransactionGeneratorConfiguration(): void { + if (this.getAutomaticTransactionGeneratorPersistentConfiguration()) { + this.saveConfiguration(); + } + } + private saveConnectorsStatus() { this.saveConfiguration(); } @@ -1532,54 +1567,79 @@ export class ChargingStation { } private saveConfiguration(): void { - if (this.configurationFile) { + if (Utils.isNotEmptyString(this.configurationFile)) { try { if (!fs.existsSync(path.dirname(this.configurationFile))) { fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true }); } - const configurationData: ChargingStationConfiguration = - Utils.cloneObject(this.getConfigurationFromFile()) ?? {}; + let configurationData: ChargingStationConfiguration = + Utils.cloneObject(this.getConfigurationFromFile()) ?? {}; if (this.getStationInfoPersistentConfiguration() && this.stationInfo) { configurationData.stationInfo = this.stationInfo; + } else { + delete configurationData.stationInfo; } if (this.getOcppPersistentConfiguration() && this.ocppConfiguration?.configurationKey) { configurationData.configurationKey = this.ocppConfiguration.configurationKey; + } else { + delete configurationData.configurationKey; + } + configurationData = merge( + configurationData, + buildChargingStationAutomaticTransactionGeneratorConfiguration(this) + ); + if ( + !this.getAutomaticTransactionGeneratorPersistentConfiguration() || + !this.getAutomaticTransactionGeneratorConfiguration() + ) { + delete configurationData.automaticTransactionGenerator; } if (this.connectors.size > 0) { - configurationData.connectorsStatus = [...this.connectors.values()].map( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest - ); + configurationData.connectorsStatus = buildConnectorsStatus(this); + } else { + delete configurationData.connectorsStatus; } if (this.evses.size > 0) { - configurationData.evsesStatus = [...this.evses.values()].map((evseStatus) => { - const status = { - ...evseStatus, - connectorsStatus: [...evseStatus.connectors.values()].map( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest - ), - }; - delete status.connectors; - return status as EvseStatusConfiguration; - }); + configurationData.evsesStatus = buildEvsesStatus(this); + } else { + delete configurationData.evsesStatus; } delete configurationData.configurationHash; const configurationHash = crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) - .update(JSON.stringify(configurationData)) + .update( + JSON.stringify({ + stationInfo: configurationData.stationInfo, + configurationKey: configurationData.configurationKey, + automaticTransactionGenerator: configurationData.automaticTransactionGenerator, + } as ChargingStationConfiguration) + ) .digest('hex'); if (this.configurationFileHash !== configurationHash) { - configurationData.configurationHash = configurationHash; - const measureId = `${FileType.ChargingStationConfiguration} write`; - const beginId = PerformanceStatistics.beginMeasure(measureId); - const fileDescriptor = fs.openSync(this.configurationFile, 'w'); - fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8'); - fs.closeSync(fileDescriptor); - PerformanceStatistics.endMeasure(measureId, beginId); - this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash); - this.sharedLRUCache.setChargingStationConfiguration(configurationData); - this.configurationFileHash = configurationHash; + AsyncLock.acquire(AsyncLockType.configuration) + .then(() => { + configurationData.configurationHash = configurationHash; + const measureId = `${FileType.ChargingStationConfiguration} write`; + const beginId = PerformanceStatistics.beginMeasure(measureId); + const fileDescriptor = fs.openSync(this.configurationFile, 'w'); + fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8'); + fs.closeSync(fileDescriptor); + PerformanceStatistics.endMeasure(measureId, beginId); + this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash); + this.sharedLRUCache.setChargingStationConfiguration(configurationData); + this.configurationFileHash = configurationHash; + }) + .catch((error) => { + handleFileException( + this.configurationFile, + FileType.ChargingStationConfiguration, + error as NodeJS.ErrnoException, + this.logPrefix() + ); + }) + .finally(() => { + AsyncLock.release(AsyncLockType.configuration).catch(Constants.EMPTY_FUNCTION); + }); } else { logger.debug( `${this.logPrefix()} Not saving unchanged charging station configuration file ${ @@ -1588,7 +1648,7 @@ export class ChargingStation { ); } } catch (error) { - FileUtils.handleFileException( + handleFileException( this.configurationFile, FileType.ChargingStationConfiguration, error as NodeJS.ErrnoException, @@ -1607,18 +1667,11 @@ export class ChargingStation { } private getOcppConfigurationFromFile(): ChargingStationOcppConfiguration | undefined { - let configuration: ChargingStationConfiguration | undefined; - if (this.getOcppPersistentConfiguration() === true) { - const configurationFromFile = this.getConfigurationFromFile(); - configuration = configurationFromFile?.configurationKey && configurationFromFile; + const configurationKey = this.getConfigurationFromFile()?.configurationKey; + if (this.getOcppPersistentConfiguration() === true && configurationKey) { + return { configurationKey }; } - if (!Utils.isNullOrUndefined(configuration)) { - delete configuration.stationInfo; - delete configuration.connectorsStatus; - delete configuration.evsesStatus; - delete configuration.configurationHash; - } - return configuration; + return undefined; } private getOcppConfiguration(): ChargingStationOcppConfiguration | undefined { @@ -1646,11 +1699,11 @@ export class ChargingStation { skipBufferingOnError: true, }); if (this.isRegistered() === false) { - this.getRegistrationMaxRetries() !== -1 && registrationRetryCount++; + this.getRegistrationMaxRetries() !== -1 && ++registrationRetryCount; await Utils.sleep( this?.bootNotificationResponse?.interval ? this.bootNotificationResponse.interval * 1000 - : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL + : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL ); } } while ( @@ -1660,7 +1713,7 @@ export class ChargingStation { ); } if (this.isRegistered() === true) { - if (this.isInAcceptedState() === true) { + if (this.inAcceptedState() === true) { await this.startMessageSequence(); } } else { @@ -1670,7 +1723,7 @@ export class ChargingStation { } this.wsConnectionRestarted = false; this.autoReconnectRetryCount = 0; - parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); + parentPort?.postMessage(buildUpdatedMessage(this)); } else { logger.warn( `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.toString()} failed` @@ -1700,7 +1753,7 @@ export class ChargingStation { this.started === true && (await this.reconnect()); break; } - parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); + parentPort?.postMessage(buildUpdatedMessage(this)); } private getCachedRequest(messageType: MessageType, messageId: string): CachedRequest | undefined { @@ -1810,7 +1863,7 @@ export class ChargingStation { logger.error(`${this.logPrefix()} ${errorMsg}`); throw new OCPPError(ErrorType.PROTOCOL_ERROR, errorMsg); } - parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); + parentPort?.postMessage(buildUpdatedMessage(this)); } else { throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not an array', null, { request, @@ -2009,7 +2062,8 @@ export class ChargingStation { await OCPPServiceUtils.sendAndSetConnectorStatus( this, connectorId, - connectorBootStatus + connectorBootStatus, + evseId ); } } @@ -2037,7 +2091,7 @@ export class ChargingStation { } // Start the ATG - if (this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true) { + if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) { this.startAutomaticTransactionGenerator(); } this.wsConnectionRestarted === true && this.flushMessageBuffer(); @@ -2069,7 +2123,8 @@ export class ChargingStation { OCPPServiceUtils.buildStatusNotificationRequest( this, connectorId, - ConnectorStatusEnum.Unavailable + ConnectorStatusEnum.Unavailable, + evseId ) ); delete connectorStatus?.status; @@ -2141,6 +2196,7 @@ export class ChargingStation { } private getConfiguredSupervisionUrl(): URL { + let configuredSupervisionUrl: string; const supervisionUrls = this.stationInfo?.supervisionUrls ?? Configuration.getSupervisionUrls(); if (Utils.isNotEmptyArray(supervisionUrls)) { let configuredSupervisionUrlIndex: number; @@ -2162,9 +2218,16 @@ export class ChargingStation { configuredSupervisionUrlIndex = (this.index - 1) % supervisionUrls.length; break; } - return new URL(supervisionUrls[configuredSupervisionUrlIndex]); + configuredSupervisionUrl = supervisionUrls[configuredSupervisionUrlIndex]; + } else { + configuredSupervisionUrl = supervisionUrls as string; } - return new URL(supervisionUrls as string); + if (Utils.isNotEmptyString(configuredSupervisionUrl)) { + return new URL(configuredSupervisionUrl); + } + const errorMsg = 'No supervision url(s) configured'; + logger.error(`${this.logPrefix()} ${errorMsg}`); + throw new BaseError(`${errorMsg}`); } private stopHeartbeat(): void { @@ -2191,14 +2254,14 @@ export class ChargingStation { // Stop heartbeat this.stopHeartbeat(); // Stop the ATG if needed - if (this.automaticTransactionGenerator?.configuration?.stopOnConnectionFailure === true) { + if (this.getAutomaticTransactionGeneratorConfiguration().stopOnConnectionFailure === true) { this.stopAutomaticTransactionGenerator(); } if ( this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() || this.getAutoReconnectMaxRetries() === -1 ) { - this.autoReconnectRetryCount++; + ++this.autoReconnectRetryCount; const reconnectDelay = this.getReconnectExponentialDelay() ? Utils.exponentialDelay(this.autoReconnectRetryCount) : this.getConnectionTimeout() * 1000; @@ -2233,10 +2296,4 @@ export class ChargingStation { ); } } - - private getAutomaticTransactionGeneratorConfigurationFromTemplate(): - | AutomaticTransactionGeneratorConfiguration - | undefined { - return this.getTemplateFromFile()?.AutomaticTransactionGenerator; - } }