private wsConnectionRestarted: boolean;
private autoReconnectRetryCount: number;
private templateFileWatcher!: fs.FSWatcher | undefined;
+ private templateFileHash!: string;
private readonly sharedLRUCache: SharedLRUCache;
private webSocketPingSetInterval!: NodeJS.Timeout;
private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel;
public getNumberOfConnectors(): number {
if (this.hasEvses) {
+ if (this.evses.size === 0) {
+ throw new BaseError('Evses not initialized, cannot get number of connectors');
+ }
let numberOfConnectors = 0;
for (const [evseId, evseStatus] of this.evses) {
if (evseId > 0) {
}
return numberOfConnectors;
}
+ if (this.connectors.size === 0) {
+ throw new BaseError('Connectors not initialized, cannot get number of connectors');
+ }
return this.connectors.has(0) ? this.connectors.size - 1 : this.connectors.size;
}
public getNumberOfEvses(): number {
+ if (this.evses.size === 0) {
+ throw new BaseError('Evses not initialized, cannot get number of evses');
+ }
return this.evses.has(0) ? this.evses.size - 1 : this.evses.size;
}
this.templateFile
} file have changed, reload`
);
- this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
+ this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
// Initialize
this.initialize();
// Restart the ATG
}
this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
this.templateFileWatcher?.close();
- this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
+ this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
delete this.bootNotificationResponse;
this.started = false;
parentPort?.postMessage(MessageChannelUtils.buildStoppedMessage(this));
private getTemplateFromFile(): ChargingStationTemplate | undefined {
let template: ChargingStationTemplate;
try {
- if (this.sharedLRUCache.hasChargingStationTemplate(this.stationInfo?.templateHash)) {
- template = this.sharedLRUCache.getChargingStationTemplate(this.stationInfo.templateHash);
+ if (this.sharedLRUCache.hasChargingStationTemplate(this.templateFileHash)) {
+ template = this.sharedLRUCache.getChargingStationTemplate(this.templateFileHash);
} else {
const measureId = `${FileType.ChargingStationTemplate} read`;
const beginId = PerformanceStatistics.beginMeasure(measureId);
.update(JSON.stringify(template))
.digest('hex');
this.sharedLRUCache.setChargingStationTemplate(template);
+ this.templateFileHash = template.templateHash;
}
} catch (error) {
FileUtils.handleFileException(
stationInfo.resetTime = !Utils.isNullOrUndefined(stationTemplate?.resetTime)
? stationTemplate.resetTime * 1000
: Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
- // Initialize evses or connectors if needed (FIXME: should be factored out but connectors and evses configuration are only available in templates)
- this.initializeConnectorsOrEvses(stationInfo);
stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
+ if (stationInfo?.Connectors) {
+ ChargingStationUtils.checkConnectorsConfiguration(
+ stationInfo,
+ this.templateFile,
+ this.logPrefix()
+ );
+ }
delete stationInfo?.Connectors;
delete stationInfo?.Evses;
return stationInfo;
}
private initialize(): void {
+ const stationTemplate = this.getTemplateFromFile();
+ if (Utils.isNullOrUndefined(stationTemplate)) {
+ const errorMsg = `Failed to read charging station template file ${this.templateFile}`;
+ logger.error(`${this.logPrefix()} ${errorMsg}`);
+ throw new BaseError(errorMsg);
+ }
this.configurationFile = path.join(
path.dirname(this.templateFile.replace('station-templates', 'configurations')),
- `${ChargingStationUtils.getHashId(this.index, this.getTemplateFromFile())}.json`
+ `${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json`
);
+ this.initializeConnectorsOrEvses(stationTemplate);
this.stationInfo = this.getStationInfo();
if (
this.stationInfo.firmwareStatus === FirmwareStatus.Installing &&
this.saveOcppConfiguration();
}
- private initializeConnectorsOrEvses(stationInfo: ChargingStationInfo) {
- if (stationInfo?.Connectors && !stationInfo?.Evses) {
- this.initializeConnectors(stationInfo);
- } else if (stationInfo?.Evses && !stationInfo?.Connectors) {
- this.initializeEvses(stationInfo);
- } else if (stationInfo?.Evses && stationInfo?.Connectors) {
+ private initializeConnectorsOrEvses(stationTemplate: ChargingStationTemplate) {
+ if (stationTemplate?.Connectors && !stationTemplate?.Evses) {
+ this.initializeConnectors(stationTemplate);
+ } else if (stationTemplate?.Evses && !stationTemplate?.Connectors) {
+ this.initializeEvses(stationTemplate);
+ } else if (stationTemplate?.Evses && stationTemplate?.Connectors) {
const errorMsg = `Connectors and evses defined at the same time in template file ${this.templateFile}`;
logger.error(`${this.logPrefix()} ${errorMsg}`);
throw new BaseError(errorMsg);
}
}
- private initializeConnectors(stationInfo: ChargingStationInfo): void {
- if (!stationInfo?.Connectors && this.connectors.size === 0) {
+ private initializeConnectors(stationTemplate: ChargingStationTemplate): void {
+ if (!stationTemplate?.Connectors && this.connectors.size === 0) {
const errorMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`;
logger.error(`${this.logPrefix()} ${errorMsg}`);
throw new BaseError(errorMsg);
}
- if (!stationInfo?.Connectors[0]) {
+ if (!stationTemplate?.Connectors[0]) {
logger.warn(
`${this.logPrefix()} Charging station information from template ${
this.templateFile
} with no connector id 0 configuration`
);
}
- if (stationInfo?.Connectors) {
- const configuredMaxConnectors =
- ChargingStationUtils.getConfiguredNumberOfConnectors(stationInfo);
- ChargingStationUtils.checkConfiguredMaxConnectors(
- configuredMaxConnectors,
- this.templateFile,
- this.logPrefix()
- );
+ if (stationTemplate?.Connectors) {
+ const { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors } =
+ ChargingStationUtils.checkConnectorsConfiguration(
+ stationTemplate,
+ this.templateFile,
+ this.logPrefix()
+ );
const connectorsConfigHash = crypto
.createHash(Constants.DEFAULT_HASH_ALGORITHM)
- .update(`${JSON.stringify(stationInfo?.Connectors)}${configuredMaxConnectors.toString()}`)
+ .update(
+ `${JSON.stringify(stationTemplate?.Connectors)}${configuredMaxConnectors.toString()}`
+ )
.digest('hex');
const connectorsConfigChanged =
this.connectors?.size !== 0 && this.connectorsConfigurationHash !== connectorsConfigHash;
if (this.connectors?.size === 0 || connectorsConfigChanged) {
connectorsConfigChanged && this.connectors.clear();
this.connectorsConfigurationHash = connectorsConfigHash;
- const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
- stationInfo.Connectors
- );
- ChargingStationUtils.checkTemplateMaxConnectors(
- templateMaxConnectors,
- this.templateFile,
- this.logPrefix()
- );
- const templateMaxAvailableConnectors = stationInfo?.Connectors[0]
- ? templateMaxConnectors - 1
- : templateMaxConnectors;
- if (
- configuredMaxConnectors > templateMaxAvailableConnectors &&
- !stationInfo?.randomConnectors
- ) {
- logger.warn(
- `${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${
- this.templateFile
- }, forcing random connector configurations affectation`
- );
- stationInfo.randomConnectors = true;
- }
if (templateMaxConnectors > 0) {
for (let connectorId = 0; connectorId <= configuredMaxConnectors; connectorId++) {
if (
connectorId === 0 &&
- (!stationInfo?.Connectors[connectorId] ||
- this.getUseConnectorId0(stationInfo) === false)
+ (!stationTemplate?.Connectors[connectorId] ||
+ this.getUseConnectorId0(stationTemplate) === false)
) {
continue;
}
const templateConnectorId =
- connectorId > 0 && stationInfo?.randomConnectors
+ connectorId > 0 && stationTemplate?.randomConnectors
? Utils.getRandomInteger(templateMaxAvailableConnectors, 1)
: connectorId;
- const connectorStatus = stationInfo?.Connectors[templateConnectorId];
+ const connectorStatus = stationTemplate?.Connectors[templateConnectorId];
ChargingStationUtils.checkStationInfoConnectorStatus(
templateConnectorId,
connectorStatus,
}
}
- private initializeEvses(stationInfo: ChargingStationInfo): void {
- if (!stationInfo?.Evses && this.evses.size === 0) {
+ private initializeEvses(stationTemplate: ChargingStationTemplate): void {
+ if (!stationTemplate?.Evses && this.evses.size === 0) {
const errorMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
logger.error(`${this.logPrefix()} ${errorMsg}`);
throw new BaseError(errorMsg);
}
- if (!stationInfo?.Evses[0]) {
+ if (!stationTemplate?.Evses[0]) {
logger.warn(
`${this.logPrefix()} Charging station information from template ${
this.templateFile
} with no evse id 0 configuration`
);
}
- if (!stationInfo?.Evses[0]?.Connectors[0]) {
+ if (!stationTemplate?.Evses[0]?.Connectors[0]) {
logger.warn(
`${this.logPrefix()} Charging station information from template ${
this.templateFile
} with evse id 0 with no connector id 0 configuration`
);
}
- if (stationInfo?.Evses) {
+ if (stationTemplate?.Evses) {
const evsesConfigHash = crypto
.createHash(Constants.DEFAULT_HASH_ALGORITHM)
- .update(`${JSON.stringify(stationInfo?.Evses)}`)
+ .update(`${JSON.stringify(stationTemplate?.Evses)}`)
.digest('hex');
const evsesConfigChanged =
this.evses?.size !== 0 && this.evsesConfigurationHash !== evsesConfigHash;
if (this.evses?.size === 0 || evsesConfigChanged) {
evsesConfigChanged && this.evses.clear();
this.evsesConfigurationHash = evsesConfigHash;
- const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationInfo?.Evses);
+ const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationTemplate?.Evses);
if (templateMaxEvses > 0) {
- for (const evse in stationInfo.Evses) {
+ for (const evse in stationTemplate.Evses) {
const evseId = Utils.convertToInt(evse);
this.evses.set(evseId, {
connectors: ChargingStationUtils.buildConnectorsMap(
- stationInfo?.Evses[evse]?.Connectors,
+ stationTemplate?.Evses[evse]?.Connectors,
this.logPrefix(),
this.templateFile
),
fs.readFileSync(this.configurationFile, 'utf8')
) as ChargingStationConfiguration;
PerformanceStatistics.endMeasure(measureId, beginId);
- this.configurationFileHash = configuration.configurationHash;
this.sharedLRUCache.setChargingStationConfiguration(configuration);
+ this.configurationFileHash = configuration.configurationHash;
}
} catch (error) {
FileUtils.handleFileException(
fs.closeSync(fileDescriptor);
PerformanceStatistics.endMeasure(measureId, beginId);
this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
- this.configurationFileHash = configurationHash;
this.sharedLRUCache.setChargingStationConfiguration(configurationData);
+ this.configurationFileHash = configurationHash;
} else {
logger.debug(
`${this.logPrefix()} Not saving unchanged charging station configuration file ${
);
}
- private getUseConnectorId0(stationInfo?: ChargingStationInfo): boolean {
- return (stationInfo ?? this.stationInfo)?.useConnectorId0 ?? true;
+ private getUseConnectorId0(stationTemplate?: ChargingStationTemplate): boolean {
+ return stationTemplate?.useConnectorId0 ?? true;
}
private async stopRunningTransactions(reason = StopTransactionReason.NONE): Promise<void> {
return Object.keys(connectors).length;
}
- public static checkTemplateMaxConnectors(
- templateMaxConnectors: number,
- templateFile: string,
- logPrefix: 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`
- );
- }
- }
-
public static getBootConnectorStatus(
chargingStation: ChargingStation,
connectorId: number,
return connectorBootStatus;
}
- public static getConfiguredNumberOfConnectors(stationInfo: ChargingStationInfo): number {
- let configuredMaxConnectors: number;
- if (Utils.isNotEmptyArray(stationInfo.numberOfConnectors) === true) {
- const numberOfConnectors = stationInfo.numberOfConnectors as number[];
- configuredMaxConnectors =
- numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
- } else if (Utils.isUndefined(stationInfo.numberOfConnectors) === false) {
- configuredMaxConnectors = stationInfo.numberOfConnectors as number;
- } else if (stationInfo.Connectors && !stationInfo.Evses) {
- configuredMaxConnectors = stationInfo?.Connectors[0]
- ? ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors) - 1
- : ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors);
- } else if (stationInfo.Evses && !stationInfo.Connectors) {
- configuredMaxConnectors = 0;
- for (const evse in stationInfo.Evses) {
- if (evse === '0') {
- continue;
- }
- configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
- stationInfo.Evses[evse].Connectors
- );
- }
- }
- return configuredMaxConnectors;
- }
-
- public static checkConfiguredMaxConnectors(
- configuredMaxConnectors: number,
+ public static checkConnectorsConfiguration(
+ stationTemplate: ChargingStationTemplate | ChargingStationInfo,
templateFile: string,
logPrefix: string
- ): void {
- if (configuredMaxConnectors <= 0) {
+ ): {
+ configuredMaxConnectors: number;
+ templateMaxConnectors: number;
+ templateMaxAvailableConnectors: number;
+ } {
+ const configuredMaxConnectors =
+ ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate);
+ ChargingStationUtils.checkConfiguredMaxConnectors(
+ configuredMaxConnectors,
+ templateFile,
+ logPrefix
+ );
+ const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
+ stationTemplate.Connectors
+ );
+ ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, templateFile, logPrefix);
+ const templateMaxAvailableConnectors = stationTemplate?.Connectors[0]
+ ? templateMaxConnectors - 1
+ : templateMaxConnectors;
+ if (
+ configuredMaxConnectors > templateMaxAvailableConnectors &&
+ !stationTemplate?.randomConnectors
+ ) {
logger.warn(
- `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+ `${logPrefix} Number of connectors exceeds the number of connector configurations in template ${templateFile}, forcing random connector configurations affectation`
);
+ stationTemplate.randomConnectors = true;
}
+ return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors };
}
public static checkStationInfoConnectorStatus(
);
}
+ private static getConfiguredNumberOfConnectors(
+ stationTemplate: ChargingStationTemplate | ChargingStationInfo
+ ): number {
+ let configuredMaxConnectors: number;
+ if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
+ const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
+ configuredMaxConnectors =
+ numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
+ } else if (Utils.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
+ );
+ }
+ }
+ return configuredMaxConnectors;
+ }
+
+ private static checkConfiguredMaxConnectors(
+ configuredMaxConnectors: number,
+ templateFile: string,
+ logPrefix: string
+ ): void {
+ if (configuredMaxConnectors <= 0) {
+ logger.warn(
+ `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+ );
+ }
+ }
+
+ private static checkTemplateMaxConnectors(
+ templateMaxConnectors: number,
+ templateFile: string,
+ logPrefix: 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`
+ );
+ }
+ }
+
private static initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
connectorStatus.availability = AvailabilityType.Operative;
connectorStatus.idTagLocalAuthorized = false;