+ // Initialize connectors status
+ for (const connectorId of this.connectors.keys()) {
+ if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
+ logger.warn(
+ `${this.logPrefix()} Connector ${connectorId} at initialization has a transaction started: ${
+ this.getConnectorStatus(connectorId)?.transactionId
+ }`
+ );
+ }
+ if (
+ connectorId > 0 &&
+ Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionStarted)
+ ) {
+ this.initializeConnectorStatus(this.getConnectorStatus(connectorId));
+ }
+ }
+ }
+
+ private buildConnectorsMap(
+ connectors: Record<string, ConnectorStatus>
+ ): Map<number, ConnectorStatus> {
+ const connectorsMap = new Map<number, ConnectorStatus>();
+ for (const connector in connectors) {
+ const connectorStatus = connectors[connector];
+ const connectorId = Utils.convertToInt(connector);
+ this.checkStationInfoConnectorStatus(connectorId, connectorStatus);
+ connectorsMap.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+ connectorsMap.get(connectorId).availability = AvailabilityType.Operative;
+ if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) {
+ connectorsMap.get(connectorId).chargingProfiles = [];
+ }
+ }
+ return connectorsMap;
+ }
+
+ private initializeConnectorsMapStatus(connectors: Map<number, ConnectorStatus>): void {
+ for (const connectorId of connectors.keys()) {
+ if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) {
+ logger.warn(
+ `${this.logPrefix()} Connector ${connectorId} at initialization has a transaction started: ${
+ connectors.get(connectorId)?.transactionId
+ }`
+ );
+ }
+ if (
+ connectorId > 0 &&
+ Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted)
+ ) {
+ this.initializeConnectorStatus(connectors.get(connectorId));
+ }
+ }
+ }
+
+ private initializeEvses(stationInfo: ChargingStationInfo): void {
+ if (!stationInfo?.Evses && this.evses.size === 0) {
+ const logMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
+ logger.warn(`${this.logPrefix()} ${logMsg}`);
+ return;
+ }
+ if (!stationInfo?.Evses[0]) {
+ logger.warn(
+ `${this.logPrefix()} Charging station information from template ${
+ this.templateFile
+ } with no evse id 0 configuration`
+ );
+ }
+ if (stationInfo?.Evses) {
+ const evsesConfigHash = crypto
+ .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ .update(`${JSON.stringify(stationInfo?.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;
+ for (const evse in stationInfo?.Evses) {
+ this.evses.set(Utils.convertToInt(evse), {
+ connectors: this.buildConnectorsMap(stationInfo?.Evses[evse]?.Connectors),
+ availability: AvailabilityType.Operative,
+ });
+ this.initializeConnectorsMapStatus(this.evses.get(Utils.convertToInt(evse))?.connectors);
+ }
+ }
+ } else {
+ logger.warn(
+ `${this.logPrefix()} Charging station information from template ${
+ this.templateFile
+ } with no evses configuration defined, using already defined evses`
+ );
+ }
+ }
+
+ private checkStationInfoConnectorStatus(
+ connectorId: number,
+ connectorStatus: ConnectorStatus
+ ): void {
+ if (!Utils.isNullOrUndefined(connectorStatus?.status)) {
+ logger.warn(
+ `${this.logPrefix()} Charging station information from template ${
+ this.templateFile
+ } with connector ${connectorId} status configuration defined, undefine it`
+ );
+ delete connectorStatus.status;
+ }
+ }
+
+ private getConfigurationFromFile(): ChargingStationConfiguration | undefined {
+ let configuration: ChargingStationConfiguration | undefined;
+ if (this.configurationFile && fs.existsSync(this.configurationFile)) {
+ try {
+ if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) {
+ configuration = this.sharedLRUCache.getChargingStationConfiguration(
+ this.configurationFileHash
+ );
+ } else {
+ const measureId = `${FileType.ChargingStationConfiguration} read`;
+ const beginId = PerformanceStatistics.beginMeasure(measureId);
+ configuration = JSON.parse(
+ fs.readFileSync(this.configurationFile, 'utf8')
+ ) as ChargingStationConfiguration;
+ PerformanceStatistics.endMeasure(measureId, beginId);
+ this.configurationFileHash = configuration.configurationHash;
+ this.sharedLRUCache.setChargingStationConfiguration(configuration);
+ }
+ } catch (error) {
+ FileUtils.handleFileException(
+ this.configurationFile,
+ FileType.ChargingStationConfiguration,
+ error as NodeJS.ErrnoException,
+ this.logPrefix()
+ );
+ }
+ }
+ return configuration;
+ }
+
+ private saveConfiguration(): void {
+ if (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()) ?? {};
+ this.ocppConfiguration?.configurationKey &&
+ (configurationData.configurationKey = this.ocppConfiguration.configurationKey);
+ this.stationInfo && (configurationData.stationInfo = this.stationInfo);
+ delete configurationData.configurationHash;
+ const configurationHash = crypto
+ .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ .update(JSON.stringify(configurationData))
+ .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.configurationFileHash = configurationHash;
+ this.sharedLRUCache.setChargingStationConfiguration(configurationData);
+ } else {
+ logger.debug(
+ `${this.logPrefix()} Not saving unchanged charging station configuration file ${
+ this.configurationFile
+ }`
+ );
+ }
+ } catch (error) {
+ FileUtils.handleFileException(
+ this.configurationFile,
+ FileType.ChargingStationConfiguration,
+ error as NodeJS.ErrnoException,
+ this.logPrefix()
+ );