From fba11dc656de000473d0639be238c8151f217d93 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Wed, 5 Jul 2023 17:58:21 +0200 Subject: [PATCH] refactor: split ChargingStationUtils class static methods into functions MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../AutomaticTransactionGenerator.ts | 13 +- src/charging-station/Bootstrap.ts | 4 +- src/charging-station/ChargingStation.ts | 111 +- src/charging-station/ChargingStationUtils.ts | 1356 ++++++++--------- src/charging-station/IdTagsCache.ts | 6 +- src/charging-station/index.ts | 2 +- .../ocpp/1.6/OCPP16IncomingRequestService.ts | 12 +- .../ocpp/1.6/OCPP16ResponseService.ts | 8 +- .../ocpp/1.6/OCPP16ServiceUtils.ts | 4 +- .../ocpp/OCPPIncomingRequestService.ts | 8 +- 10 files changed, 731 insertions(+), 793 deletions(-) diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index 233f2519..3c2a2c38 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -3,7 +3,7 @@ import { AsyncResource } from 'node:async_hooks'; import type { ChargingStation } from './ChargingStation'; -import { ChargingStationUtils } from './ChargingStationUtils'; +import { checkChargingStation } from './ChargingStationUtils'; import { IdTagsCache } from './IdTagsCache'; import { BaseError } from '../exception'; import { PerformanceStatistics } from '../performance'; @@ -68,9 +68,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { } public start(): void { - if ( - ChargingStationUtils.checkChargingStation(this.chargingStation, this.logPrefix()) === false - ) { + if (checkChargingStation(this.chargingStation, this.logPrefix()) === false) { return; } if (this.started === true) { @@ -103,12 +101,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { } public startConnector(connectorId: number): void { - if ( - ChargingStationUtils.checkChargingStation( - this.chargingStation, - this.logPrefix(connectorId) - ) === false - ) { + if (checkChargingStation(this.chargingStation, this.logPrefix(connectorId)) === false) { return; } if (this.connectorsStatus.has(connectorId) === false) { diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index cb4b65eb..e329a65b 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -7,7 +7,7 @@ import { isMainThread } from 'node:worker_threads'; import chalk from 'chalk'; -import { ChargingStationUtils } from './ChargingStationUtils'; +import { waitForChargingStationEvents } from './ChargingStationUtils'; import type { AbstractUIServer } from './ui-server/AbstractUIServer'; import { UIServerFactory } from './ui-server/UIServerFactory'; import { version } from '../../package.json' assert { type: 'json' }; @@ -168,7 +168,7 @@ export class Bootstrap extends EventEmitter { ) ); await Promise.race([ - ChargingStationUtils.waitForChargingStationEvents( + waitForChargingStationEvents( this, ChargingStationWorkerMessageEvents.stopped, this.numberOfChargingStations diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index af021085..ba43ff98 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -20,7 +20,28 @@ import { type RawData, WebSocket } from 'ws'; import { AutomaticTransactionGenerator } from './AutomaticTransactionGenerator'; import { ChargingStationWorkerBroadcastChannel } from './broadcast-channel/ChargingStationWorkerBroadcastChannel'; import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; -import { ChargingStationUtils } from './ChargingStationUtils'; +import { + buildConnectorsMap, + checkConnectorsConfiguration, + checkStationInfoConnectorStatus, + checkTemplate, + countReservableConnectors, + createBootNotificationRequest, + createSerialNumber, + getAmperageLimitationUnitDivider, + getBootConnectorStatus, + getChargingStationConnectorChargingProfilesPowerLimit, + getChargingStationId, + getDefaultVoltageOut, + getHashId, + getIdTagsFile, + getMaxNumberOfEvses, + getPhaseRotationValue, + initializeConnectorsMapStatus, + propagateSerialNumber, + stationTemplateToStationInfo, + warnTemplateKeysDeprecation, +} from './ChargingStationUtils'; import { IdTagsCache } from './IdTagsCache'; import { OCPP16IncomingRequestService, @@ -211,16 +232,14 @@ export class ChargingStation { ` ${ (isNotEmptyString(this?.stationInfo?.chargingStationId) ? this?.stationInfo?.chargingStationId - : ChargingStationUtils.getChargingStationId(this.index, this.getTemplateFromFile())) ?? + : getChargingStationId(this.index, this.getTemplateFromFile())) ?? 'Error at building log prefix' } |` ); }; public hasIdTags(): boolean { - return isNotEmptyArray( - this.idTagsCache.getIdTags(ChargingStationUtils.getIdTagsFile(this.stationInfo)) - ); + return isNotEmptyArray(this.idTagsCache.getIdTags(getIdTagsFile(this.stationInfo))); } public getEnableStatistics(): boolean { @@ -337,7 +356,7 @@ export class ChargingStation { } public getVoltageOut(stationInfo?: ChargingStationInfo): number | undefined { - const defaultVoltageOut = ChargingStationUtils.getDefaultVoltageOut( + const defaultVoltageOut = getDefaultVoltageOut( this.getCurrentOutType(stationInfo), this.logPrefix(), this.templateFile @@ -369,7 +388,7 @@ export class ChargingStation { } const connectorMaximumPower = this.getMaximumPower() / this.powerDivider; const connectorChargingProfilesPowerLimit = - ChargingStationUtils.getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId); + getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId); return Math.min( isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower, isNaN(connectorAmperageLimitationPowerLimit) @@ -1077,12 +1096,10 @@ export class ChargingStation { let reservableConnectors = 0; if (this.hasEvses) { for (const evseStatus of this.evses.values()) { - reservableConnectors += ChargingStationUtils.countReservableConnectors( - evseStatus.connectors - ); + reservableConnectors += countReservableConnectors(evseStatus.connectors); } } else { - reservableConnectors = ChargingStationUtils.countReservableConnectors(this.connectors); + reservableConnectors = countReservableConnectors(this.connectors); } return reservableConnectors - this.getNumberOfReservationsOnConnectorZero(); } @@ -1163,28 +1180,16 @@ export class ChargingStation { private getStationInfoFromTemplate(): ChargingStationInfo { const stationTemplate: ChargingStationTemplate | undefined = this.getTemplateFromFile(); - ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); - ChargingStationUtils.warnTemplateKeysDeprecation( - stationTemplate, - this.logPrefix(), - this.templateFile - ); + checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); + warnTemplateKeysDeprecation(stationTemplate, this.logPrefix(), this.templateFile); if (stationTemplate?.Connectors) { - ChargingStationUtils.checkConnectorsConfiguration( - stationTemplate, - this.logPrefix(), - this.templateFile - ); + checkConnectorsConfiguration(stationTemplate, this.logPrefix(), this.templateFile); } - const stationInfo: ChargingStationInfo = - ChargingStationUtils.stationTemplateToStationInfo(stationTemplate); - stationInfo.hashId = ChargingStationUtils.getHashId(this.index, stationTemplate); - stationInfo.chargingStationId = ChargingStationUtils.getChargingStationId( - this.index, - stationTemplate - ); + const stationInfo: ChargingStationInfo = stationTemplateToStationInfo(stationTemplate); + stationInfo.hashId = getHashId(this.index, stationTemplate); + stationInfo.chargingStationId = getChargingStationId(this.index, stationTemplate); stationInfo.ocppVersion = stationTemplate?.ocppVersion ?? OCPPVersion.VERSION_16; - ChargingStationUtils.createSerialNumber(stationTemplate, stationInfo); + createSerialNumber(stationTemplate, stationInfo); if (isNotEmptyArray(stationTemplate?.power)) { stationTemplate.power = stationTemplate.power as number[]; const powerArrayRandomIndex = Math.floor(secureRandom() * stationTemplate.power.length); @@ -1248,7 +1253,7 @@ export class ChargingStation { return stationInfoFromFile; } stationInfoFromFile && - ChargingStationUtils.propagateSerialNumber( + propagateSerialNumber( this.getTemplateFromFile(), stationInfoFromFile, stationInfoFromTemplate @@ -1283,10 +1288,10 @@ export class ChargingStation { private initialize(): void { const stationTemplate = this.getTemplateFromFile(); - ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); + checkTemplate(stationTemplate, this.logPrefix(), this.templateFile); this.configurationFile = join( dirname(this.templateFile.replace('station-templates', 'configurations')), - `${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json` + `${getHashId(this.index, stationTemplate)}.json` ); const chargingStationConfiguration = this.getConfigurationFromFile(); if ( @@ -1325,9 +1330,7 @@ export class ChargingStation { this.configuredSupervisionUrl ); } - this.bootNotificationRequest = ChargingStationUtils.createBootNotificationRequest( - this.stationInfo - ); + this.bootNotificationRequest = createBootNotificationRequest(this.stationInfo); this.powerDivider = this.getPowerDivider(); // OCPP configuration this.ocppConfiguration = this.getOcppConfiguration(); @@ -1425,8 +1428,7 @@ export class ChargingStation { this, this.stationInfo.amperageLimitationOcppKey, ( - this.stationInfo.maximumAmperage * - ChargingStationUtils.getAmperageLimitationUnitDivider(this.stationInfo) + this.stationInfo.maximumAmperage * getAmperageLimitationUnitDivider(this.stationInfo) ).toString() ); } @@ -1472,14 +1474,14 @@ export class ChargingStation { for (const evseStatus of this.evses.values()) { for (const connectorId of evseStatus.connectors.keys()) { connectorsPhaseRotation.push( - ChargingStationUtils.getPhaseRotationValue(connectorId, this.getNumberOfPhases()) + getPhaseRotationValue(connectorId, this.getNumberOfPhases()) ); } } } else { for (const connectorId of this.connectors.keys()) { connectorsPhaseRotation.push( - ChargingStationUtils.getPhaseRotationValue(connectorId, this.getNumberOfPhases()) + getPhaseRotationValue(connectorId, this.getNumberOfPhases()) ); } } @@ -1593,11 +1595,7 @@ export class ChargingStation { } if (stationTemplate?.Connectors) { const { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors } = - ChargingStationUtils.checkConnectorsConfiguration( - stationTemplate, - this.logPrefix(), - this.templateFile - ); + checkConnectorsConfiguration(stationTemplate, this.logPrefix(), this.templateFile); const connectorsConfigHash = createHash(Constants.DEFAULT_HASH_ALGORITHM) .update( `${JSON.stringify(stationTemplate?.Connectors)}${configuredMaxConnectors.toString()}` @@ -1622,7 +1620,7 @@ export class ChargingStation { ? getRandomInteger(templateMaxAvailableConnectors, 1) : connectorId; const connectorStatus = stationTemplate?.Connectors[templateConnectorId]; - ChargingStationUtils.checkStationInfoConnectorStatus( + checkStationInfoConnectorStatus( templateConnectorId, connectorStatus, this.logPrefix(), @@ -1630,7 +1628,7 @@ export class ChargingStation { ); this.connectors.set(connectorId, cloneObject(connectorStatus)); } - ChargingStationUtils.initializeConnectorsMapStatus(this.connectors, this.logPrefix()); + initializeConnectorsMapStatus(this.connectors, this.logPrefix()); this.saveConnectorsStatus(); } else { logger.warn( @@ -1678,22 +1676,19 @@ export class ChargingStation { if (this.evses?.size === 0 || evsesConfigChanged) { evsesConfigChanged && this.evses.clear(); this.evsesConfigurationHash = evsesConfigHash; - const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationTemplate?.Evses); + const templateMaxEvses = getMaxNumberOfEvses(stationTemplate?.Evses); if (templateMaxEvses > 0) { for (const evse in stationTemplate.Evses) { const evseId = convertToInt(evse); this.evses.set(evseId, { - connectors: ChargingStationUtils.buildConnectorsMap( + connectors: buildConnectorsMap( stationTemplate?.Evses[evse]?.Connectors, this.logPrefix(), this.templateFile ), availability: AvailabilityType.Operative, }); - ChargingStationUtils.initializeConnectorsMapStatus( - this.evses.get(evseId)?.connectors, - this.logPrefix() - ); + initializeConnectorsMapStatus(this.evses.get(evseId)?.connectors, this.logPrefix()); } this.saveEvsesStatus(); } else { @@ -2224,7 +2219,7 @@ export class ChargingStation { this, this.stationInfo.amperageLimitationOcppKey )?.value - ) / ChargingStationUtils.getAmperageLimitationUnitDivider(this.stationInfo) + ) / getAmperageLimitationUnitDivider(this.stationInfo) ); } } @@ -2247,11 +2242,7 @@ export class ChargingStation { for (const [evseId, evseStatus] of this.evses) { if (evseId > 0) { for (const [connectorId, connectorStatus] of evseStatus.connectors) { - const connectorBootStatus = ChargingStationUtils.getBootConnectorStatus( - this, - connectorId, - connectorStatus - ); + const connectorBootStatus = getBootConnectorStatus(this, connectorId, connectorStatus); await OCPPServiceUtils.sendAndSetConnectorStatus( this, connectorId, @@ -2264,7 +2255,7 @@ export class ChargingStation { } else { for (const connectorId of this.connectors.keys()) { if (connectorId > 0) { - const connectorBootStatus = ChargingStationUtils.getBootConnectorStatus( + const connectorBootStatus = getBootConnectorStatus( this, connectorId, this.getConnectorStatus(connectorId) diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index 3e5d658d..66a4725f 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -49,748 +49,714 @@ import { const moduleName = 'ChargingStationUtils'; -export class ChargingStationUtils { - private constructor() { - // This is intentional - } - - public static getChargingStationId( - index: number, - stationTemplate: ChargingStationTemplate - ): string { - // In case of multiple instances: add instance index to charging station id - const instanceIndex = process.env.CF_INSTANCE_INDEX ?? 0; - const idSuffix = stationTemplate?.nameSuffix ?? ''; - const idStr = `000000000${index.toString()}`; - return stationTemplate?.fixedName - ? stationTemplate.baseName - : `${stationTemplate.baseName}-${instanceIndex.toString()}${idStr.substring( - idStr.length - 4 - )}${idSuffix}`; - } - - public static countReservableConnectors(connectors: Map) { - let reservableConnectors = 0; - for (const [connectorId, connectorStatus] of connectors) { - if (connectorId === 0) { - continue; - } - if (connectorStatus.status === ConnectorStatusEnum.Available) { - ++reservableConnectors; - } +export const getChargingStationId = ( + index: number, + stationTemplate: ChargingStationTemplate +): string => { + // In case of multiple instances: add instance index to charging station id + const instanceIndex = process.env.CF_INSTANCE_INDEX ?? 0; + const idSuffix = stationTemplate?.nameSuffix ?? ''; + const idStr = `000000000${index.toString()}`; + return stationTemplate?.fixedName + ? stationTemplate.baseName + : `${stationTemplate.baseName}-${instanceIndex.toString()}${idStr.substring( + idStr.length - 4 + )}${idSuffix}`; +}; + +export const countReservableConnectors = (connectors: Map) => { + let reservableConnectors = 0; + for (const [connectorId, connectorStatus] of connectors) { + if (connectorId === 0) { + continue; } - return reservableConnectors; - } - - public static getHashId(index: number, stationTemplate: ChargingStationTemplate): string { - const chargingStationInfo = { - chargePointModel: stationTemplate.chargePointModel, - chargePointVendor: stationTemplate.chargePointVendor, - ...(!isUndefined(stationTemplate.chargeBoxSerialNumberPrefix) && { - chargeBoxSerialNumber: stationTemplate.chargeBoxSerialNumberPrefix, - }), - ...(!isUndefined(stationTemplate.chargePointSerialNumberPrefix) && { - chargePointSerialNumber: stationTemplate.chargePointSerialNumberPrefix, - }), - ...(!isUndefined(stationTemplate.meterSerialNumberPrefix) && { - meterSerialNumber: stationTemplate.meterSerialNumberPrefix, - }), - ...(!isUndefined(stationTemplate.meterType) && { - meterType: stationTemplate.meterType, - }), - }; - return createHash(Constants.DEFAULT_HASH_ALGORITHM) - .update( - `${JSON.stringify(chargingStationInfo)}${ChargingStationUtils.getChargingStationId( - index, - stationTemplate - )}` - ) - .digest('hex'); - } - - public static checkChargingStation(chargingStation: ChargingStation, logPrefix: string): boolean { - if (chargingStation.started === false && chargingStation.starting === false) { - logger.warn(`${logPrefix} charging station is stopped, cannot proceed`); - return false; + if (connectorStatus.status === ConnectorStatusEnum.Available) { + ++reservableConnectors; } - return true; } - - public static getPhaseRotationValue( - connectorId: number, - numberOfPhases: number - ): string | undefined { - // AC/DC - if (connectorId === 0 && numberOfPhases === 0) { - return `${connectorId}.${ConnectorPhaseRotation.RST}`; - } else if (connectorId > 0 && numberOfPhases === 0) { - return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`; - // AC - } else if (connectorId > 0 && numberOfPhases === 1) { - return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`; - } else if (connectorId > 0 && numberOfPhases === 3) { - return `${connectorId}.${ConnectorPhaseRotation.RST}`; - } - } - - public static getMaxNumberOfEvses(evses: Record): number { - if (!evses) { - return -1; - } - return Object.keys(evses).length; - } - - public static getMaxNumberOfConnectors(connectors: Record): number { - if (!connectors) { - return -1; - } - return Object.keys(connectors).length; + return reservableConnectors; +}; + +export const getHashId = (index: number, stationTemplate: ChargingStationTemplate): string => { + const chargingStationInfo = { + chargePointModel: stationTemplate.chargePointModel, + chargePointVendor: stationTemplate.chargePointVendor, + ...(!isUndefined(stationTemplate.chargeBoxSerialNumberPrefix) && { + chargeBoxSerialNumber: stationTemplate.chargeBoxSerialNumberPrefix, + }), + ...(!isUndefined(stationTemplate.chargePointSerialNumberPrefix) && { + chargePointSerialNumber: stationTemplate.chargePointSerialNumberPrefix, + }), + ...(!isUndefined(stationTemplate.meterSerialNumberPrefix) && { + meterSerialNumber: stationTemplate.meterSerialNumberPrefix, + }), + ...(!isUndefined(stationTemplate.meterType) && { + meterType: stationTemplate.meterType, + }), + }; + return createHash(Constants.DEFAULT_HASH_ALGORITHM) + .update(`${JSON.stringify(chargingStationInfo)}${getChargingStationId(index, stationTemplate)}`) + .digest('hex'); +}; + +export const checkChargingStation = ( + chargingStation: ChargingStation, + logPrefix: string +): boolean => { + if (chargingStation.started === false && chargingStation.starting === false) { + logger.warn(`${logPrefix} charging station is stopped, cannot proceed`); + return false; + } + return true; +}; + +export const getPhaseRotationValue = ( + connectorId: number, + numberOfPhases: number +): string | undefined => { + // AC/DC + if (connectorId === 0 && numberOfPhases === 0) { + return `${connectorId}.${ConnectorPhaseRotation.RST}`; + } else if (connectorId > 0 && numberOfPhases === 0) { + return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`; + // AC + } else if (connectorId > 0 && numberOfPhases === 1) { + return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`; + } else if (connectorId > 0 && numberOfPhases === 3) { + return `${connectorId}.${ConnectorPhaseRotation.RST}`; + } +}; + +export const getMaxNumberOfEvses = (evses: Record): number => { + if (!evses) { + return -1; + } + return Object.keys(evses).length; +}; + +const getMaxNumberOfConnectors = (connectors: Record): number => { + if (!connectors) { + return -1; + } + return Object.keys(connectors).length; +}; + +export const getBootConnectorStatus = ( + chargingStation: ChargingStation, + connectorId: number, + connectorStatus: ConnectorStatus +): ConnectorStatusEnum => { + let connectorBootStatus: ConnectorStatusEnum; + if ( + !connectorStatus?.status && + (chargingStation.isChargingStationAvailable() === false || + chargingStation.isConnectorAvailable(connectorId) === false) + ) { + connectorBootStatus = ConnectorStatusEnum.Unavailable; + } else if (!connectorStatus?.status && connectorStatus?.bootStatus) { + // Set boot status in template at startup + connectorBootStatus = connectorStatus?.bootStatus; + } else if (connectorStatus?.status) { + // Set previous status at startup + connectorBootStatus = connectorStatus?.status; + } else { + // Set default status + connectorBootStatus = ConnectorStatusEnum.Available; + } + return connectorBootStatus; +}; + +export const checkTemplate = ( + stationTemplate: ChargingStationTemplate, + logPrefix: string, + templateFile: string +): void => { + if (isNullOrUndefined(stationTemplate)) { + const errorMsg = `Failed to read charging station template file ${templateFile}`; + logger.error(`${logPrefix} ${errorMsg}`); + throw new BaseError(errorMsg); + } + if (isEmptyObject(stationTemplate)) { + const errorMsg = `Empty charging station information from template file ${templateFile}`; + logger.error(`${logPrefix} ${errorMsg}`); + throw new BaseError(errorMsg); + } + if (isEmptyObject(stationTemplate.AutomaticTransactionGenerator)) { + stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION; + logger.warn( + `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`, + Constants.DEFAULT_ATG_CONFIGURATION + ); } - - public static getBootConnectorStatus( - chargingStation: ChargingStation, - connectorId: number, - connectorStatus: ConnectorStatus - ): ConnectorStatusEnum { - let connectorBootStatus: ConnectorStatusEnum; - if ( - !connectorStatus?.status && - (chargingStation.isChargingStationAvailable() === false || - chargingStation.isConnectorAvailable(connectorId) === false) - ) { - connectorBootStatus = ConnectorStatusEnum.Unavailable; - } else if (!connectorStatus?.status && connectorStatus?.bootStatus) { - // Set boot status in template at startup - connectorBootStatus = connectorStatus?.bootStatus; - } else if (connectorStatus?.status) { - // Set previous status at startup - connectorBootStatus = connectorStatus?.status; - } else { - // Set default status - connectorBootStatus = ConnectorStatusEnum.Available; - } - return connectorBootStatus; + if (isNullOrUndefined(stationTemplate.idTagsFile) || isEmptyString(stationTemplate.idTagsFile)) { + logger.warn( + `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator` + ); } - - public static checkTemplate( - stationTemplate: ChargingStationTemplate, - logPrefix: string, - templateFile: string +}; + +export const checkConnectorsConfiguration = ( + stationTemplate: ChargingStationTemplate, + logPrefix: string, + templateFile: string +): { + configuredMaxConnectors: number; + templateMaxConnectors: number; + templateMaxAvailableConnectors: number; +} => { + const configuredMaxConnectors = getConfiguredNumberOfConnectors(stationTemplate); + checkConfiguredMaxConnectors(configuredMaxConnectors, logPrefix, templateFile); + const templateMaxConnectors = getMaxNumberOfConnectors(stationTemplate.Connectors); + checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile); + const templateMaxAvailableConnectors = stationTemplate?.Connectors[0] + ? templateMaxConnectors - 1 + : templateMaxConnectors; + if ( + configuredMaxConnectors > templateMaxAvailableConnectors && + !stationTemplate?.randomConnectors ) { - if (isNullOrUndefined(stationTemplate)) { - const errorMsg = `Failed to read charging station template file ${templateFile}`; - logger.error(`${logPrefix} ${errorMsg}`); - throw new BaseError(errorMsg); - } - if (isEmptyObject(stationTemplate)) { - const errorMsg = `Empty charging station information from template file ${templateFile}`; - logger.error(`${logPrefix} ${errorMsg}`); - throw new BaseError(errorMsg); - } - if (isEmptyObject(stationTemplate.AutomaticTransactionGenerator)) { - stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION; - logger.warn( - `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`, - Constants.DEFAULT_ATG_CONFIGURATION - ); - } - if ( - isNullOrUndefined(stationTemplate.idTagsFile) || - isEmptyString(stationTemplate.idTagsFile) - ) { - logger.warn( - `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator` - ); - } - } - - public static checkConnectorsConfiguration( - stationTemplate: ChargingStationTemplate, - logPrefix: string, - templateFile: string - ): { - configuredMaxConnectors: number; - templateMaxConnectors: number; - templateMaxAvailableConnectors: number; - } { - const configuredMaxConnectors = - ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate); - ChargingStationUtils.checkConfiguredMaxConnectors( - configuredMaxConnectors, - logPrefix, - templateFile + logger.warn( + `${logPrefix} Number of connectors exceeds the number of connector configurations in template ${templateFile}, forcing random connector configurations affectation` ); - const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors( - stationTemplate.Connectors + stationTemplate.randomConnectors = true; + } + return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors }; +}; + +export const checkStationInfoConnectorStatus = ( + connectorId: number, + connectorStatus: ConnectorStatus, + logPrefix: string, + templateFile: string +): void => { + if (!isNullOrUndefined(connectorStatus?.status)) { + logger.warn( + `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId} status configuration defined, undefine it` ); - ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile); - const templateMaxAvailableConnectors = stationTemplate?.Connectors[0] - ? templateMaxConnectors - 1 - : templateMaxConnectors; - if ( - configuredMaxConnectors > templateMaxAvailableConnectors && - !stationTemplate?.randomConnectors - ) { - logger.warn( - `${logPrefix} Number of connectors exceeds the number of connector configurations in template ${templateFile}, forcing random connector configurations affectation` - ); - stationTemplate.randomConnectors = true; + delete connectorStatus.status; + } +}; + +export const buildConnectorsMap = ( + connectors: Record, + logPrefix: string, + templateFile: string +): Map => { + const connectorsMap = new Map(); + if (getMaxNumberOfConnectors(connectors) > 0) { + for (const connector in connectors) { + const connectorStatus = connectors[connector]; + const connectorId = convertToInt(connector); + checkStationInfoConnectorStatus(connectorId, connectorStatus, logPrefix, templateFile); + connectorsMap.set(connectorId, cloneObject(connectorStatus)); } - return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors }; + } else { + logger.warn( + `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map` + ); } + return connectorsMap; +}; - public static checkStationInfoConnectorStatus( - connectorId: number, - connectorStatus: ConnectorStatus, - logPrefix: string, - templateFile: string - ): void { - if (!isNullOrUndefined(connectorStatus?.status)) { +export const initializeConnectorsMapStatus = ( + connectors: Map, + logPrefix: string +): void => { + for (const connectorId of connectors.keys()) { + if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) { logger.warn( - `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId} status configuration defined, undefine it` + `${logPrefix} Connector id ${connectorId} at initialization has a transaction started with id ${ + connectors.get(connectorId)?.transactionId + }` ); - delete connectorStatus.status; } - } - - public static buildConnectorsMap( - connectors: Record, - logPrefix: string, - templateFile: string - ): Map { - const connectorsMap = new Map(); - if (ChargingStationUtils.getMaxNumberOfConnectors(connectors) > 0) { - for (const connector in connectors) { - const connectorStatus = connectors[connector]; - const connectorId = convertToInt(connector); - ChargingStationUtils.checkStationInfoConnectorStatus( - connectorId, - connectorStatus, - logPrefix, - templateFile - ); - connectorsMap.set(connectorId, cloneObject(connectorStatus)); - } - } else { - logger.warn( - `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map` - ); - } - return connectorsMap; - } - - public static initializeConnectorsMapStatus( - connectors: Map, - logPrefix: string - ): void { - for (const connectorId of connectors.keys()) { - if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) { - logger.warn( - `${logPrefix} Connector id ${connectorId} at initialization has a transaction started with id ${ - connectors.get(connectorId)?.transactionId - }` - ); - } - if (connectorId === 0) { - connectors.get(connectorId).availability = AvailabilityType.Operative; - if (isUndefined(connectors.get(connectorId)?.chargingProfiles)) { - connectors.get(connectorId).chargingProfiles = []; - } - } else if ( - connectorId > 0 && - isNullOrUndefined(connectors.get(connectorId)?.transactionStarted) - ) { - ChargingStationUtils.initializeConnectorStatus(connectors.get(connectorId)); + if (connectorId === 0) { + connectors.get(connectorId).availability = AvailabilityType.Operative; + if (isUndefined(connectors.get(connectorId)?.chargingProfiles)) { + connectors.get(connectorId).chargingProfiles = []; } + } else if ( + connectorId > 0 && + isNullOrUndefined(connectors.get(connectorId)?.transactionStarted) + ) { + initializeConnectorStatus(connectors.get(connectorId)); } } - - public static resetConnectorStatus(connectorStatus: ConnectorStatus): void { - connectorStatus.idTagLocalAuthorized = false; - connectorStatus.idTagAuthorized = false; - connectorStatus.transactionRemoteStarted = false; - connectorStatus.transactionStarted = false; - delete connectorStatus?.localAuthorizeIdTag; - delete connectorStatus?.authorizeIdTag; - delete connectorStatus?.transactionId; - delete connectorStatus?.transactionIdTag; - connectorStatus.transactionEnergyActiveImportRegisterValue = 0; - delete connectorStatus?.transactionBeginMeterValue; - } - - public static createBootNotificationRequest( - stationInfo: ChargingStationInfo, - bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp - ): BootNotificationRequest { - const ocppVersion = stationInfo.ocppVersion ?? OCPPVersion.VERSION_16; - switch (ocppVersion) { - case OCPPVersion.VERSION_16: - return { - chargePointModel: stationInfo.chargePointModel, - chargePointVendor: stationInfo.chargePointVendor, - ...(!isUndefined(stationInfo.chargeBoxSerialNumber) && { - chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber, - }), - ...(!isUndefined(stationInfo.chargePointSerialNumber) && { - chargePointSerialNumber: stationInfo.chargePointSerialNumber, - }), +}; + +export const resetConnectorStatus = (connectorStatus: ConnectorStatus): void => { + connectorStatus.idTagLocalAuthorized = false; + connectorStatus.idTagAuthorized = false; + connectorStatus.transactionRemoteStarted = false; + connectorStatus.transactionStarted = false; + delete connectorStatus?.localAuthorizeIdTag; + delete connectorStatus?.authorizeIdTag; + delete connectorStatus?.transactionId; + delete connectorStatus?.transactionIdTag; + connectorStatus.transactionEnergyActiveImportRegisterValue = 0; + delete connectorStatus?.transactionBeginMeterValue; +}; + +export const createBootNotificationRequest = ( + stationInfo: ChargingStationInfo, + bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp +): BootNotificationRequest => { + const ocppVersion = stationInfo.ocppVersion ?? OCPPVersion.VERSION_16; + switch (ocppVersion) { + case OCPPVersion.VERSION_16: + return { + chargePointModel: stationInfo.chargePointModel, + chargePointVendor: stationInfo.chargePointVendor, + ...(!isUndefined(stationInfo.chargeBoxSerialNumber) && { + chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber, + }), + ...(!isUndefined(stationInfo.chargePointSerialNumber) && { + chargePointSerialNumber: stationInfo.chargePointSerialNumber, + }), + ...(!isUndefined(stationInfo.firmwareVersion) && { + firmwareVersion: stationInfo.firmwareVersion, + }), + ...(!isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), + ...(!isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), + ...(!isUndefined(stationInfo.meterSerialNumber) && { + meterSerialNumber: stationInfo.meterSerialNumber, + }), + ...(!isUndefined(stationInfo.meterType) && { + meterType: stationInfo.meterType, + }), + } as OCPP16BootNotificationRequest; + case OCPPVersion.VERSION_20: + case OCPPVersion.VERSION_201: + return { + reason: bootReason, + chargingStation: { + model: stationInfo.chargePointModel, + vendorName: stationInfo.chargePointVendor, ...(!isUndefined(stationInfo.firmwareVersion) && { firmwareVersion: stationInfo.firmwareVersion, }), - ...(!isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), - ...(!isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), - ...(!isUndefined(stationInfo.meterSerialNumber) && { - meterSerialNumber: stationInfo.meterSerialNumber, + ...(!isUndefined(stationInfo.chargeBoxSerialNumber) && { + serialNumber: stationInfo.chargeBoxSerialNumber, }), - ...(!isUndefined(stationInfo.meterType) && { - meterType: stationInfo.meterType, + ...((!isUndefined(stationInfo.iccid) || !isUndefined(stationInfo.imsi)) && { + modem: { + ...(!isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), + ...(!isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), + }, }), - } as OCPP16BootNotificationRequest; - case OCPPVersion.VERSION_20: - case OCPPVersion.VERSION_201: - return { - reason: bootReason, - chargingStation: { - model: stationInfo.chargePointModel, - vendorName: stationInfo.chargePointVendor, - ...(!isUndefined(stationInfo.firmwareVersion) && { - firmwareVersion: stationInfo.firmwareVersion, - }), - ...(!isUndefined(stationInfo.chargeBoxSerialNumber) && { - serialNumber: stationInfo.chargeBoxSerialNumber, - }), - ...((!isUndefined(stationInfo.iccid) || !isUndefined(stationInfo.imsi)) && { - modem: { - ...(!isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), - ...(!isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), - }, - }), - }, - } as OCPP20BootNotificationRequest; - } - } - - public static warnTemplateKeysDeprecation( - stationTemplate: ChargingStationTemplate, - logPrefix: string, - templateFile: string - ) { - const templateKeys: { key: string; deprecatedKey: string }[] = [ - { key: 'supervisionUrls', deprecatedKey: 'supervisionUrl' }, - { key: 'idTagsFile', deprecatedKey: 'authorizationFile' }, - ]; - for (const templateKey of templateKeys) { - ChargingStationUtils.warnDeprecatedTemplateKey( - stationTemplate, - templateKey.deprecatedKey, - logPrefix, - templateFile, - `Use '${templateKey.key}' instead` - ); - ChargingStationUtils.convertDeprecatedTemplateKey( - stationTemplate, - templateKey.deprecatedKey, - templateKey.key - ); - } - } - - public static stationTemplateToStationInfo( - stationTemplate: ChargingStationTemplate - ): ChargingStationInfo { - stationTemplate = cloneObject(stationTemplate); - delete stationTemplate.power; - delete stationTemplate.powerUnit; - delete stationTemplate?.Connectors; - delete stationTemplate?.Evses; - delete stationTemplate.Configuration; - delete stationTemplate.AutomaticTransactionGenerator; - delete stationTemplate.chargeBoxSerialNumberPrefix; - delete stationTemplate.chargePointSerialNumberPrefix; - delete stationTemplate.meterSerialNumberPrefix; - return stationTemplate as unknown as ChargingStationInfo; - } - - public static createSerialNumber( - stationTemplate: ChargingStationTemplate, - stationInfo: ChargingStationInfo, - params: { - randomSerialNumberUpperCase?: boolean; - randomSerialNumber?: boolean; - } = { - randomSerialNumberUpperCase: true, - randomSerialNumber: true, - } - ): void { - params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params }; - const serialNumberSuffix = params?.randomSerialNumber - ? ChargingStationUtils.getRandomSerialNumberSuffix({ - upperCase: params.randomSerialNumberUpperCase, - }) - : ''; - isNotEmptyString(stationTemplate?.chargePointSerialNumberPrefix) && - (stationInfo.chargePointSerialNumber = `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`); - isNotEmptyString(stationTemplate?.chargeBoxSerialNumberPrefix) && - (stationInfo.chargeBoxSerialNumber = `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`); - isNotEmptyString(stationTemplate?.meterSerialNumberPrefix) && - (stationInfo.meterSerialNumber = `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`); - } - - public static propagateSerialNumber( - stationTemplate: ChargingStationTemplate, - stationInfoSrc: ChargingStationInfo, - stationInfoDst: ChargingStationInfo - ) { - if (!stationInfoSrc || !stationTemplate) { - throw new BaseError( - 'Missing charging station template or existing configuration to propagate serial number' - ); - } - stationTemplate?.chargePointSerialNumberPrefix && stationInfoSrc?.chargePointSerialNumber - ? (stationInfoDst.chargePointSerialNumber = stationInfoSrc.chargePointSerialNumber) - : stationInfoDst?.chargePointSerialNumber && delete stationInfoDst.chargePointSerialNumber; - stationTemplate?.chargeBoxSerialNumberPrefix && stationInfoSrc?.chargeBoxSerialNumber - ? (stationInfoDst.chargeBoxSerialNumber = stationInfoSrc.chargeBoxSerialNumber) - : stationInfoDst?.chargeBoxSerialNumber && delete stationInfoDst.chargeBoxSerialNumber; - stationTemplate?.meterSerialNumberPrefix && stationInfoSrc?.meterSerialNumber - ? (stationInfoDst.meterSerialNumber = stationInfoSrc.meterSerialNumber) - : stationInfoDst?.meterSerialNumber && delete stationInfoDst.meterSerialNumber; + }, + } as OCPP20BootNotificationRequest; + } +}; + +export const warnTemplateKeysDeprecation = ( + stationTemplate: ChargingStationTemplate, + logPrefix: string, + templateFile: string +) => { + const templateKeys: { key: string; deprecatedKey: string }[] = [ + { key: 'supervisionUrls', deprecatedKey: 'supervisionUrl' }, + { key: 'idTagsFile', deprecatedKey: 'authorizationFile' }, + ]; + for (const templateKey of templateKeys) { + warnDeprecatedTemplateKey( + stationTemplate, + templateKey.deprecatedKey, + logPrefix, + templateFile, + `Use '${templateKey.key}' instead` + ); + convertDeprecatedTemplateKey(stationTemplate, templateKey.deprecatedKey, templateKey.key); + } +}; + +export const stationTemplateToStationInfo = ( + stationTemplate: ChargingStationTemplate +): ChargingStationInfo => { + stationTemplate = cloneObject(stationTemplate); + delete stationTemplate.power; + delete stationTemplate.powerUnit; + delete stationTemplate?.Connectors; + delete stationTemplate?.Evses; + delete stationTemplate.Configuration; + delete stationTemplate.AutomaticTransactionGenerator; + delete stationTemplate.chargeBoxSerialNumberPrefix; + delete stationTemplate.chargePointSerialNumberPrefix; + delete stationTemplate.meterSerialNumberPrefix; + return stationTemplate as unknown as ChargingStationInfo; +}; + +export const createSerialNumber = ( + stationTemplate: ChargingStationTemplate, + stationInfo: ChargingStationInfo, + params: { + randomSerialNumberUpperCase?: boolean; + randomSerialNumber?: boolean; + } = { + randomSerialNumberUpperCase: true, + randomSerialNumber: true, + } +): void => { + params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params }; + const serialNumberSuffix = params?.randomSerialNumber + ? getRandomSerialNumberSuffix({ + upperCase: params.randomSerialNumberUpperCase, + }) + : ''; + isNotEmptyString(stationTemplate?.chargePointSerialNumberPrefix) && + (stationInfo.chargePointSerialNumber = `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`); + isNotEmptyString(stationTemplate?.chargeBoxSerialNumberPrefix) && + (stationInfo.chargeBoxSerialNumber = `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`); + isNotEmptyString(stationTemplate?.meterSerialNumberPrefix) && + (stationInfo.meterSerialNumber = `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`); +}; + +export const propagateSerialNumber = ( + stationTemplate: ChargingStationTemplate, + stationInfoSrc: ChargingStationInfo, + stationInfoDst: ChargingStationInfo +) => { + if (!stationInfoSrc || !stationTemplate) { + throw new BaseError( + 'Missing charging station template or existing configuration to propagate serial number' + ); } - - public static getAmperageLimitationUnitDivider(stationInfo: ChargingStationInfo): number { - let unitDivider = 1; - switch (stationInfo.amperageLimitationUnit) { - case AmpereUnits.DECI_AMPERE: - unitDivider = 10; - break; - case AmpereUnits.CENTI_AMPERE: - unitDivider = 100; - break; - case AmpereUnits.MILLI_AMPERE: - unitDivider = 1000; - break; - } - return unitDivider; + stationTemplate?.chargePointSerialNumberPrefix && stationInfoSrc?.chargePointSerialNumber + ? (stationInfoDst.chargePointSerialNumber = stationInfoSrc.chargePointSerialNumber) + : stationInfoDst?.chargePointSerialNumber && delete stationInfoDst.chargePointSerialNumber; + stationTemplate?.chargeBoxSerialNumberPrefix && stationInfoSrc?.chargeBoxSerialNumber + ? (stationInfoDst.chargeBoxSerialNumber = stationInfoSrc.chargeBoxSerialNumber) + : stationInfoDst?.chargeBoxSerialNumber && delete stationInfoDst.chargeBoxSerialNumber; + stationTemplate?.meterSerialNumberPrefix && stationInfoSrc?.meterSerialNumber + ? (stationInfoDst.meterSerialNumber = stationInfoSrc.meterSerialNumber) + : stationInfoDst?.meterSerialNumber && delete stationInfoDst.meterSerialNumber; +}; + +export const getAmperageLimitationUnitDivider = (stationInfo: ChargingStationInfo): number => { + let unitDivider = 1; + switch (stationInfo.amperageLimitationUnit) { + case AmpereUnits.DECI_AMPERE: + unitDivider = 10; + break; + case AmpereUnits.CENTI_AMPERE: + unitDivider = 100; + break; + case AmpereUnits.MILLI_AMPERE: + unitDivider = 1000; + break; + } + return unitDivider; +}; + +export const getChargingStationConnectorChargingProfilesPowerLimit = ( + chargingStation: ChargingStation, + connectorId: number +): number | undefined => { + let limit: number, matchingChargingProfile: ChargingProfile; + // Get charging profiles for connector and sort by stack level + const chargingProfiles = + cloneObject( + chargingStation.getConnectorStatus(connectorId)?.chargingProfiles + )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? []; + // Get profiles on connector 0 + if (chargingStation.getConnectorStatus(0)?.chargingProfiles) { + chargingProfiles.push( + ...cloneObject( + chargingStation.getConnectorStatus(0).chargingProfiles + ).sort((a, b) => b.stackLevel - a.stackLevel) + ); } - - public static getChargingStationConnectorChargingProfilesPowerLimit( - chargingStation: ChargingStation, - connectorId: number - ): number | undefined { - let limit: number, matchingChargingProfile: ChargingProfile; - // Get charging profiles for connector and sort by stack level - const chargingProfiles = - cloneObject( - chargingStation.getConnectorStatus(connectorId)?.chargingProfiles - )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? []; - // Get profiles on connector 0 - if (chargingStation.getConnectorStatus(0)?.chargingProfiles) { - chargingProfiles.push( - ...cloneObject( - chargingStation.getConnectorStatus(0).chargingProfiles - ).sort((a, b) => b.stackLevel - a.stackLevel) - ); - } - if (isNotEmptyArray(chargingProfiles)) { - const result = ChargingStationUtils.getLimitFromChargingProfiles( - chargingProfiles, - chargingStation.logPrefix() - ); - if (!isNullOrUndefined(result)) { - limit = result?.limit; - matchingChargingProfile = result?.matchingChargingProfile; - switch (chargingStation.getCurrentOutType()) { - case CurrentType.AC: - limit = - matchingChargingProfile.chargingSchedule.chargingRateUnit === - ChargingRateUnitType.WATT - ? limit - : ACElectricUtils.powerTotal( - chargingStation.getNumberOfPhases(), - chargingStation.getVoltageOut(), - limit - ); - break; - case CurrentType.DC: - limit = - matchingChargingProfile.chargingSchedule.chargingRateUnit === - ChargingRateUnitType.WATT - ? limit - : DCElectricUtils.power(chargingStation.getVoltageOut(), limit); - } - const connectorMaximumPower = - chargingStation.getMaximumPower() / chargingStation.powerDivider; - if (limit > connectorMaximumPower) { - logger.error( - `${chargingStation.logPrefix()} Charging profile id ${ - matchingChargingProfile.chargingProfileId - } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`, - result - ); - limit = connectorMaximumPower; - } + if (isNotEmptyArray(chargingProfiles)) { + const result = getLimitFromChargingProfiles(chargingProfiles, chargingStation.logPrefix()); + if (!isNullOrUndefined(result)) { + limit = result?.limit; + matchingChargingProfile = result?.matchingChargingProfile; + switch (chargingStation.getCurrentOutType()) { + case CurrentType.AC: + limit = + matchingChargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT + ? limit + : ACElectricUtils.powerTotal( + chargingStation.getNumberOfPhases(), + chargingStation.getVoltageOut(), + limit + ); + break; + case CurrentType.DC: + limit = + matchingChargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT + ? limit + : DCElectricUtils.power(chargingStation.getVoltageOut(), limit); + } + const connectorMaximumPower = + chargingStation.getMaximumPower() / chargingStation.powerDivider; + if (limit > connectorMaximumPower) { + logger.error( + `${chargingStation.logPrefix()} Charging profile id ${ + matchingChargingProfile.chargingProfileId + } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`, + result + ); + limit = connectorMaximumPower; } } - return limit; - } - - public static getDefaultVoltageOut( - currentType: CurrentType, - logPrefix: string, - templateFile: string - ): Voltage { - const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; - let defaultVoltageOut: number; - switch (currentType) { - case CurrentType.AC: - defaultVoltageOut = Voltage.VOLTAGE_230; - break; - case CurrentType.DC: - defaultVoltageOut = Voltage.VOLTAGE_400; - break; - default: - logger.error(`${logPrefix} ${errorMsg}`); - throw new BaseError(errorMsg); - } - return defaultVoltageOut; } - - public static getIdTagsFile(stationInfo: ChargingStationInfo): string | undefined { - return ( - stationInfo.idTagsFile && - join(dirname(fileURLToPath(import.meta.url)), 'assets', basename(stationInfo.idTagsFile)) - ); + return limit; +}; + +export const getDefaultVoltageOut = ( + currentType: CurrentType, + logPrefix: string, + templateFile: string +): Voltage => { + const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; + let defaultVoltageOut: number; + switch (currentType) { + case CurrentType.AC: + defaultVoltageOut = Voltage.VOLTAGE_230; + break; + case CurrentType.DC: + defaultVoltageOut = Voltage.VOLTAGE_400; + break; + default: + logger.error(`${logPrefix} ${errorMsg}`); + throw new BaseError(errorMsg); } - - public static waitForChargingStationEvents = async ( - emitter: EventEmitter, - event: ChargingStationWorkerMessageEvents, - eventsToWait: number - ): Promise => { - return new Promise((resolve) => { - let events = 0; - if (eventsToWait === 0) { + return defaultVoltageOut; +}; + +export const getIdTagsFile = (stationInfo: ChargingStationInfo): string | undefined => { + return ( + stationInfo.idTagsFile && + join(dirname(fileURLToPath(import.meta.url)), 'assets', basename(stationInfo.idTagsFile)) + ); +}; + +export const waitForChargingStationEvents = async ( + emitter: EventEmitter, + event: ChargingStationWorkerMessageEvents, + eventsToWait: number +): Promise => { + return new Promise((resolve) => { + let events = 0; + if (eventsToWait === 0) { + resolve(events); + } + emitter.on(event, () => { + ++events; + if (events === eventsToWait) { resolve(events); } - emitter.on(event, () => { - ++events; - if (events === eventsToWait) { - resolve(events); - } - }); }); - }; - - private static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number { - let configuredMaxConnectors: number; - if (isNotEmptyArray(stationTemplate.numberOfConnectors) === true) { - const numberOfConnectors = stationTemplate.numberOfConnectors as number[]; - configuredMaxConnectors = - numberOfConnectors[Math.floor(secureRandom() * numberOfConnectors.length)]; - } else if (isUndefined(stationTemplate.numberOfConnectors) === false) { - configuredMaxConnectors = stationTemplate.numberOfConnectors as number; - } else if (stationTemplate.Connectors && !stationTemplate.Evses) { - configuredMaxConnectors = stationTemplate?.Connectors[0] - ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1 - : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors); - } else if (stationTemplate.Evses && !stationTemplate.Connectors) { - configuredMaxConnectors = 0; - for (const evse in stationTemplate.Evses) { - if (evse === '0') { - continue; - } - configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors( - stationTemplate.Evses[evse].Connectors - ); + }); +}; + +const getConfiguredNumberOfConnectors = (stationTemplate: ChargingStationTemplate): number => { + let configuredMaxConnectors: number; + if (isNotEmptyArray(stationTemplate.numberOfConnectors) === true) { + const numberOfConnectors = stationTemplate.numberOfConnectors as number[]; + configuredMaxConnectors = + numberOfConnectors[Math.floor(secureRandom() * numberOfConnectors.length)]; + } else if (isUndefined(stationTemplate.numberOfConnectors) === false) { + configuredMaxConnectors = stationTemplate.numberOfConnectors as number; + } else if (stationTemplate.Connectors && !stationTemplate.Evses) { + configuredMaxConnectors = stationTemplate?.Connectors[0] + ? getMaxNumberOfConnectors(stationTemplate.Connectors) - 1 + : getMaxNumberOfConnectors(stationTemplate.Connectors); + } else if (stationTemplate.Evses && !stationTemplate.Connectors) { + configuredMaxConnectors = 0; + for (const evse in stationTemplate.Evses) { + if (evse === '0') { + continue; } + configuredMaxConnectors += getMaxNumberOfConnectors(stationTemplate.Evses[evse].Connectors); } - return configuredMaxConnectors; } - - private static checkConfiguredMaxConnectors( - configuredMaxConnectors: number, - logPrefix: string, - templateFile: string - ): void { - if (configuredMaxConnectors <= 0) { - logger.warn( - `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors` - ); - } + return configuredMaxConnectors; +}; + +const checkConfiguredMaxConnectors = ( + configuredMaxConnectors: number, + logPrefix: string, + templateFile: string +): void => { + if (configuredMaxConnectors <= 0) { + logger.warn( + `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors` + ); } +}; - private static checkTemplateMaxConnectors( - templateMaxConnectors: number, - logPrefix: string, - templateFile: string - ): void { - if (templateMaxConnectors === 0) { +const checkTemplateMaxConnectors = ( + templateMaxConnectors: number, + logPrefix: string, + templateFile: string +): void => { + if (templateMaxConnectors === 0) { + logger.warn( + `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration` + ); + } else if (templateMaxConnectors < 0) { + logger.error( + `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined` + ); + } +}; + +const initializeConnectorStatus = (connectorStatus: ConnectorStatus): void => { + connectorStatus.availability = AvailabilityType.Operative; + connectorStatus.idTagLocalAuthorized = false; + connectorStatus.idTagAuthorized = false; + connectorStatus.transactionRemoteStarted = false; + connectorStatus.transactionStarted = false; + connectorStatus.energyActiveImportRegisterValue = 0; + connectorStatus.transactionEnergyActiveImportRegisterValue = 0; + if (isUndefined(connectorStatus.chargingProfiles)) { + connectorStatus.chargingProfiles = []; + } +}; + +const warnDeprecatedTemplateKey = ( + template: ChargingStationTemplate, + key: string, + logPrefix: string, + templateFile: string, + logMsgToAppend = '' +): void => { + if (!isUndefined(template[key])) { + const logMsg = `Deprecated template key '${key}' usage in file '${templateFile}'${ + isNotEmptyString(logMsgToAppend) ? `. ${logMsgToAppend}` : '' + }`; + logger.warn(`${logPrefix} ${logMsg}`); + console.warn(chalk.yellow(`${logMsg}`)); + } +}; + +const convertDeprecatedTemplateKey = ( + template: ChargingStationTemplate, + deprecatedKey: string, + key: string +): void => { + if (!isUndefined(template[deprecatedKey])) { + template[key] = template[deprecatedKey] as unknown; + delete template[deprecatedKey]; + } +}; + +/** + * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority) + * + * @param chargingProfiles - + * @param logPrefix - + * @returns + */ +const getLimitFromChargingProfiles = ( + chargingProfiles: ChargingProfile[], + logPrefix: string +): { + limit: number; + matchingChargingProfile: ChargingProfile; +} | null => { + const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`; + const currentMoment = moment(); + const currentDate = new Date(); + for (const chargingProfile of chargingProfiles) { + // Set helpers + const chargingSchedule = chargingProfile.chargingSchedule; + if (!chargingSchedule?.startSchedule) { logger.warn( - `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration` + `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not defined in charging profile id ${chargingProfile.chargingProfileId}` ); - } else if (templateMaxConnectors < 0) { - logger.error( - `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined` - ); - } - } - - private static initializeConnectorStatus(connectorStatus: ConnectorStatus): void { - connectorStatus.availability = AvailabilityType.Operative; - connectorStatus.idTagLocalAuthorized = false; - connectorStatus.idTagAuthorized = false; - connectorStatus.transactionRemoteStarted = false; - connectorStatus.transactionStarted = false; - connectorStatus.energyActiveImportRegisterValue = 0; - connectorStatus.transactionEnergyActiveImportRegisterValue = 0; - if (isUndefined(connectorStatus.chargingProfiles)) { - connectorStatus.chargingProfiles = []; } - } - - private static warnDeprecatedTemplateKey( - template: ChargingStationTemplate, - key: string, - logPrefix: string, - templateFile: string, - logMsgToAppend = '' - ): void { - if (!isUndefined(template[key])) { - const logMsg = `Deprecated template key '${key}' usage in file '${templateFile}'${ - isNotEmptyString(logMsgToAppend) ? `. ${logMsgToAppend}` : '' - }`; - logger.warn(`${logPrefix} ${logMsg}`); - console.warn(chalk.yellow(`${logMsg}`)); - } - } - - private static convertDeprecatedTemplateKey( - template: ChargingStationTemplate, - deprecatedKey: string, - key: string - ): void { - if (!isUndefined(template[deprecatedKey])) { - template[key] = template[deprecatedKey] as unknown; - delete template[deprecatedKey]; - } - } - - /** - * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority) - * - * @param chargingProfiles - - * @param logPrefix - - * @returns - */ - private static getLimitFromChargingProfiles( - chargingProfiles: ChargingProfile[], - logPrefix: string - ): { - limit: number; - matchingChargingProfile: ChargingProfile; - } | null { - const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`; - const currentMoment = moment(); - const currentDate = new Date(); - for (const chargingProfile of chargingProfiles) { - // Set helpers - const chargingSchedule = chargingProfile.chargingSchedule; - if (!chargingSchedule?.startSchedule) { + // Check type (recurring) and if it is already active + // Adjust the daily recurring schedule to today + if ( + chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING && + chargingProfile.recurrencyKind === RecurrencyKindType.DAILY && + currentMoment.isAfter(chargingSchedule.startSchedule) + ) { + if (!(chargingSchedule?.startSchedule instanceof Date)) { logger.warn( - `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not defined in charging profile id ${chargingProfile.chargingProfileId}` + `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not a Date object in charging profile id ${chargingProfile.chargingProfileId}. Trying to convert it to a Date object` ); + chargingSchedule.startSchedule = new Date(chargingSchedule.startSchedule); + } + chargingSchedule.startSchedule.setFullYear( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate() + ); + // Check if the start of the schedule is yesterday + if (moment(chargingSchedule.startSchedule).isAfter(currentMoment)) { + chargingSchedule.startSchedule.setDate(currentDate.getDate() - 1); } - // Check type (recurring) and if it is already active - // Adjust the daily recurring schedule to today - if ( - chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING && - chargingProfile.recurrencyKind === RecurrencyKindType.DAILY && - currentMoment.isAfter(chargingSchedule.startSchedule) - ) { - if (!(chargingSchedule?.startSchedule instanceof Date)) { - logger.warn( - `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not a Date object in charging profile id ${chargingProfile.chargingProfileId}. Trying to convert it to a Date object` - ); - chargingSchedule.startSchedule = new Date(chargingSchedule.startSchedule); + } else if (moment(chargingSchedule.startSchedule).isAfter(currentMoment)) { + return null; + } + // Check if the charging profile is active + if ( + moment(chargingSchedule.startSchedule) + .add(chargingSchedule.duration, 's') + .isAfter(currentMoment) + ) { + let lastButOneSchedule: ChargingSchedulePeriod; + // Search the right schedule period + for (const schedulePeriod of chargingSchedule.chargingSchedulePeriod) { + // Handling of only one period + if ( + chargingSchedule.chargingSchedulePeriod.length === 1 && + schedulePeriod.startPeriod === 0 + ) { + const result = { + limit: schedulePeriod.limit, + matchingChargingProfile: chargingProfile, + }; + logger.debug(debugLogMsg, result); + return result; } - chargingSchedule.startSchedule.setFullYear( - currentDate.getFullYear(), - currentDate.getMonth(), - currentDate.getDate() - ); - // Check if the start of the schedule is yesterday - if (moment(chargingSchedule.startSchedule).isAfter(currentMoment)) { - chargingSchedule.startSchedule.setDate(currentDate.getDate() - 1); + // Find the right schedule period + if ( + moment(chargingSchedule.startSchedule) + .add(schedulePeriod.startPeriod, 's') + .isAfter(currentMoment) + ) { + // Found the schedule: last but one is the correct one + const result = { + limit: lastButOneSchedule.limit, + matchingChargingProfile: chargingProfile, + }; + logger.debug(debugLogMsg, result); + return result; } - } else if (moment(chargingSchedule.startSchedule).isAfter(currentMoment)) { - return null; - } - // Check if the charging profile is active - if ( - moment(chargingSchedule.startSchedule) - .add(chargingSchedule.duration, 's') - .isAfter(currentMoment) - ) { - let lastButOneSchedule: ChargingSchedulePeriod; - // Search the right schedule period - for (const schedulePeriod of chargingSchedule.chargingSchedulePeriod) { - // Handling of only one period - if ( - chargingSchedule.chargingSchedulePeriod.length === 1 && - schedulePeriod.startPeriod === 0 - ) { - const result = { - limit: schedulePeriod.limit, - matchingChargingProfile: chargingProfile, - }; - logger.debug(debugLogMsg, result); - return result; - } - // Find the right schedule period - if ( - moment(chargingSchedule.startSchedule) - .add(schedulePeriod.startPeriod, 's') - .isAfter(currentMoment) - ) { - // Found the schedule: last but one is the correct one - const result = { - limit: lastButOneSchedule.limit, - matchingChargingProfile: chargingProfile, - }; - logger.debug(debugLogMsg, result); - return result; - } - // Keep it - lastButOneSchedule = schedulePeriod; - // Handle the last schedule period - if ( - schedulePeriod.startPeriod === - chargingSchedule.chargingSchedulePeriod[ - chargingSchedule.chargingSchedulePeriod.length - 1 - ].startPeriod - ) { - const result = { - limit: lastButOneSchedule.limit, - matchingChargingProfile: chargingProfile, - }; - logger.debug(debugLogMsg, result); - return result; - } + // Keep it + lastButOneSchedule = schedulePeriod; + // Handle the last schedule period + if ( + schedulePeriod.startPeriod === + chargingSchedule.chargingSchedulePeriod[ + chargingSchedule.chargingSchedulePeriod.length - 1 + ].startPeriod + ) { + const result = { + limit: lastButOneSchedule.limit, + matchingChargingProfile: chargingProfile, + }; + logger.debug(debugLogMsg, result); + return result; } } } - return null; } + return null; +}; - private static getRandomSerialNumberSuffix(params?: { - randomBytesLength?: number; - upperCase?: boolean; - }): string { - const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex'); - if (params?.upperCase) { - return randomSerialNumberSuffix.toUpperCase(); - } - return randomSerialNumberSuffix; +const getRandomSerialNumberSuffix = (params?: { + randomBytesLength?: number; + upperCase?: boolean; +}): string => { + const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex'); + if (params?.upperCase) { + return randomSerialNumberSuffix.toUpperCase(); } -} + return randomSerialNumberSuffix; +}; diff --git a/src/charging-station/IdTagsCache.ts b/src/charging-station/IdTagsCache.ts index 0b3ba285..bf0838e9 100644 --- a/src/charging-station/IdTagsCache.ts +++ b/src/charging-station/IdTagsCache.ts @@ -1,7 +1,7 @@ import { type FSWatcher, readFileSync } from 'node:fs'; import type { ChargingStation } from './ChargingStation'; -import { ChargingStationUtils } from './ChargingStationUtils'; +import { getIdTagsFile } from './ChargingStationUtils'; import { FileType, IdTagDistribution } from '../types'; import { handleFileException, @@ -49,7 +49,7 @@ export class IdTagsCache { connectorId: number ): string { const hashId = chargingStation.stationInfo.hashId; - const idTagsFile = ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo); + const idTagsFile = getIdTagsFile(chargingStation.stationInfo); switch (distribution) { case IdTagDistribution.RANDOM: return this.getRandomIdTag(hashId, idTagsFile); @@ -103,7 +103,7 @@ export class IdTagsCache { } private getConnectorAffinityIdTag(chargingStation: ChargingStation, connectorId: number): string { - const file = ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo); + const file = getIdTagsFile(chargingStation.stationInfo); const idTags = this.getIdTags(file); const addressableKey = this.getIdTagsCacheIndexesAddressableKey( file, diff --git a/src/charging-station/index.ts b/src/charging-station/index.ts index e31bba09..49ae434a 100644 --- a/src/charging-station/index.ts +++ b/src/charging-station/index.ts @@ -1,4 +1,4 @@ export { Bootstrap } from './Bootstrap'; export type { ChargingStation } from './ChargingStation'; export { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; -export { ChargingStationUtils } from './ChargingStationUtils'; +export { getIdTagsFile, checkChargingStation, resetConnectorStatus } from './ChargingStationUtils'; diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 6e0b57be..218f97ea 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -13,7 +13,7 @@ import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { type ChargingStation, ChargingStationConfigurationUtils, - ChargingStationUtils, + checkChargingStation, } from '../../../charging-station'; import { OCPPError } from '../../../exception'; import { @@ -1113,10 +1113,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { maxDelay = 30, minDelay = 15 ): Promise { - if ( - ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) === - false - ) { + if (checkChargingStation(chargingStation, chargingStation.logPrefix()) === false) { return; } if (chargingStation.hasEvses) { @@ -1226,10 +1223,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { } } while (transactionsStarted); !wasTransactionsStarted && (await sleep(getRandomInteger(maxDelay, minDelay) * 1000)); - if ( - ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) === - false - ) { + if (checkChargingStation(chargingStation, chargingStation.logPrefix()) === false) { return; } await chargingStation.ocppRequestService.requestHandler< diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index fae1dd9c..372c4d72 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -8,7 +8,7 @@ import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { type ChargingStation, ChargingStationConfigurationUtils, - ChargingStationUtils, + resetConnectorStatus, } from '../../../charging-station'; import { OCPPError } from '../../../exception'; import { @@ -662,7 +662,7 @@ export class OCPP16ResponseService extends OCPPResponseService { chargingStation: ChargingStation, connectorId: number ): Promise { - ChargingStationUtils.resetConnectorStatus(chargingStation.getConnectorStatus(connectorId)); + resetConnectorStatus(chargingStation.getConnectorStatus(connectorId)); chargingStation.stopMeterValues(connectorId); parentPort?.postMessage(buildUpdatedMessage(chargingStation)); if ( @@ -726,9 +726,7 @@ export class OCPP16ResponseService extends OCPPResponseService { if (chargingStation.stationInfo.powerSharedByConnectors) { chargingStation.powerDivider--; } - ChargingStationUtils.resetConnectorStatus( - chargingStation.getConnectorStatus(transactionConnectorId) - ); + resetConnectorStatus(chargingStation.getConnectorStatus(transactionConnectorId)); chargingStation.stopMeterValues(transactionConnectorId); parentPort?.postMessage(buildUpdatedMessage(chargingStation)); const logMsg = `${chargingStation.logPrefix()} Transaction with id ${requestPayload.transactionId.toString()} STOPPED on ${ diff --git a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts index aac11154..c5345950 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts @@ -2,7 +2,7 @@ import type { JSONSchemaType } from 'ajv'; -import { type ChargingStation, ChargingStationUtils } from '../../../charging-station'; +import { type ChargingStation, getIdTagsFile } from '../../../charging-station'; import { OCPPError } from '../../../exception'; import { CurrentType, @@ -958,7 +958,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { chargingStation.hasIdTags() === true && isNotEmptyString( chargingStation.idTagsCache - .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo)) + .getIdTags(getIdTagsFile(chargingStation.stationInfo)) ?.find((tag) => tag === idTag) ) ); diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index 390feda8..66dd198d 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -5,7 +5,7 @@ import ajvFormats from 'ajv-formats'; import { OCPPConstants } from './OCPPConstants'; import { OCPPServiceUtils } from './OCPPServiceUtils'; -import { type ChargingStation, ChargingStationUtils } from '../../charging-station'; +import { type ChargingStation, getIdTagsFile } from '../../charging-station'; import { OCPPError } from '../../exception'; import type { ClearCacheResponse, @@ -104,11 +104,7 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { } protected handleRequestClearCache(chargingStation: ChargingStation): ClearCacheResponse { - if ( - chargingStation.idTagsCache.deleteIdTags( - ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo) - ) - ) { + if (chargingStation.idTagsCache.deleteIdTags(getIdTagsFile(chargingStation.stationInfo))) { return OCPPConstants.OCPP_RESPONSE_ACCEPTED; } return OCPPConstants.OCPP_RESPONSE_REJECTED; -- 2.34.1