X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcharging-station%2FChargingStation.ts;h=70f511e0878c6d16944f046dde834c73d2fdc4b7;hb=007b5bdeabda751743fdff8faac672b3ec57fb61;hp=b3d4bdd98016cbf5d35288c15bff552417859497;hpb=ae25f265d8352016040872b201f6a771e0ef2a6a;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index b3d4bdd9..70f511e0 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -54,6 +54,7 @@ import { type ErrorResponse, ErrorType, type EvseStatus, + type EvseStatusConfiguration, FileType, FirmwareStatus, type FirmwareStatusNotificationRequest, @@ -165,6 +166,10 @@ export class ChargingStation { ); } + private get hasEvses(): boolean { + return this.connectors.size === 0 && this.evses.size > 0; + } + public logPrefix = (): string => { return Utils.logPrefix( ` ${ @@ -240,16 +245,40 @@ export class ChargingStation { return this.getConnectorStatus(0)?.availability === AvailabilityType.Operative; } - public isConnectorAvailable(id: number): boolean { - return id > 0 && this.getConnectorStatus(id)?.availability === AvailabilityType.Operative; + public isConnectorAvailable(connectorId: number): boolean { + return ( + connectorId > 0 && + this.getConnectorStatus(connectorId)?.availability === AvailabilityType.Operative + ); } public getNumberOfConnectors(): number { - return this.connectors.get(0) ? this.connectors.size - 1 : this.connectors.size; + if (this.hasEvses) { + let numberOfConnectors = 0; + for (const [evseId, evseStatus] of this.evses) { + if (evseId === 0) { + continue; + } + numberOfConnectors += evseStatus.connectors.size; + } + return numberOfConnectors; + } + return this.connectors.has(0) ? this.connectors.size - 1 : this.connectors.size; + } + + public getNumberOfEvses(): number { + return this.evses.has(0) ? this.evses.size - 1 : this.evses.size; } - public getConnectorStatus(id: number): ConnectorStatus | undefined { - return this.connectors.get(id); + public getConnectorStatus(connectorId: number): ConnectorStatus | undefined { + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + if (evseStatus.connectors.has(connectorId)) { + return evseStatus.connectors.get(connectorId); + } + } + } + return this.connectors.get(connectorId); } public getCurrentOutType(stationInfo?: ChargingStationInfo): CurrentType { @@ -306,12 +335,22 @@ export class ChargingStation { } public getTransactionIdTag(transactionId: number): string | undefined { - for (const connectorId of this.connectors.keys()) { - if ( - connectorId > 0 && - this.getConnectorStatus(connectorId)?.transactionId === transactionId - ) { - return this.getConnectorStatus(connectorId)?.transactionIdTag; + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + for (const connectorStatus of evseStatus.connectors.values()) { + if (connectorStatus.transactionId === transactionId) { + return connectorStatus.transactionIdTag; + } + } + } + } else { + for (const connectorId of this.connectors.keys()) { + if ( + connectorId > 0 && + this.getConnectorStatus(connectorId)?.transactionId === transactionId + ) { + return this.getConnectorStatus(connectorId)?.transactionIdTag; + } } } } @@ -345,12 +384,22 @@ export class ChargingStation { } public getConnectorIdByTransactionId(transactionId: number): number | undefined { - for (const connectorId of this.connectors.keys()) { - if ( - connectorId > 0 && - this.getConnectorStatus(connectorId)?.transactionId === transactionId - ) { - return connectorId; + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + if (connectorStatus.transactionId === transactionId) { + return connectorId; + } + } + } + } else { + for (const connectorId of this.connectors.keys()) { + if ( + connectorId > 0 && + this.getConnectorStatus(connectorId)?.transactionId === transactionId + ) { + return connectorId; + } } } } @@ -631,7 +680,7 @@ export class ChargingStation { public saveOcppConfiguration(): void { if (this.getOcppPersistentConfiguration()) { - this.saveConfiguration(); + this.saveConfiguration({ stationInfo: false, connectors: false, evses: false }); } } @@ -952,7 +1001,7 @@ export class ChargingStation { private saveStationInfo(): void { if (this.getStationInfoPersistentConfiguration()) { - this.saveConfiguration(); + this.saveConfiguration({ ocppConfiguration: false, connectors: false, evses: false }); } } @@ -1149,17 +1198,35 @@ export class ChargingStation { ) ) { const connectorPhaseRotation = []; - for (const connectorId of this.connectors.keys()) { - // AC/DC - if (connectorId === 0 && this.getNumberOfPhases() === 0) { - connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); - } else if (connectorId > 0 && this.getNumberOfPhases() === 0) { - connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); - // AC - } else if (connectorId > 0 && this.getNumberOfPhases() === 1) { - connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); - } else if (connectorId > 0 && this.getNumberOfPhases() === 3) { - connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + for (const connectorId of evseStatus.connectors.keys()) { + // AC/DC + if (connectorId === 0 && this.getNumberOfPhases() === 0) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); + } else if (connectorId > 0 && this.getNumberOfPhases() === 0) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); + // AC + } else if (connectorId > 0 && this.getNumberOfPhases() === 1) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); + } else if (connectorId > 0 && this.getNumberOfPhases() === 3) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); + } + } + } + } else { + for (const connectorId of this.connectors.keys()) { + // AC/DC + if (connectorId === 0 && this.getNumberOfPhases() === 0) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); + } else if (connectorId > 0 && this.getNumberOfPhases() === 0) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); + // AC + } else if (connectorId > 0 && this.getNumberOfPhases() === 1) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`); + } else if (connectorId > 0 && this.getNumberOfPhases() === 3) { + connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`); + } } } ChargingStationConfigurationUtils.addConfigurationKey( @@ -1257,22 +1324,6 @@ export class ChargingStation { if (this.connectors?.size === 0 || connectorsConfigChanged) { connectorsConfigChanged && this.connectors.clear(); this.connectorsConfigurationHash = connectorsConfigHash; - const connectorZeroStatus = stationInfo?.Connectors[0]; - // Add connector id 0 - if (connectorZeroStatus && this.getUseConnectorId0(stationInfo) === true) { - ChargingStationUtils.checkStationInfoConnectorStatus( - 0, - connectorZeroStatus, - this.logPrefix(), - this.templateFile - ); - this.connectors.set(0, Utils.cloneObject(connectorZeroStatus)); - this.getConnectorStatus(0).availability = AvailabilityType.Operative; - if (Utils.isUndefined(this.getConnectorStatus(0)?.chargingProfiles)) { - this.getConnectorStatus(0).chargingProfiles = []; - } - } - // Add remaining connectors const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors( stationInfo.Connectors ); @@ -1281,9 +1332,11 @@ export class ChargingStation { this.templateFile, this.logPrefix() ); + const templateMaxAvailableConnectors = stationInfo?.Connectors[0] + ? templateMaxConnectors - 1 + : templateMaxConnectors; if ( - configuredMaxConnectors > - (stationInfo?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) && + configuredMaxConnectors > templateMaxAvailableConnectors && !stationInfo?.randomConnectors ) { logger.warn( @@ -1293,14 +1346,19 @@ export class ChargingStation { ); stationInfo.randomConnectors = true; } - const templateMaxAvailableConnectors = stationInfo?.Connectors[0] - ? templateMaxConnectors - 1 - : templateMaxConnectors; - if (templateMaxAvailableConnectors > 0) { - for (let connectorId = 1; connectorId <= configuredMaxConnectors; connectorId++) { - const templateConnectorId = stationInfo?.randomConnectors - ? Utils.getRandomInteger(templateMaxAvailableConnectors, 1) - : connectorId; + if (templateMaxConnectors > 0) { + for (let connectorId = 0; connectorId <= configuredMaxConnectors; connectorId++) { + if ( + connectorId === 0 && + (!stationInfo?.Connectors[connectorId] || + this.getUseConnectorId0(stationInfo) === false) + ) { + continue; + } + const templateConnectorId = + connectorId > 0 && stationInfo?.randomConnectors + ? Utils.getRandomInteger(templateMaxAvailableConnectors, 1) + : connectorId; const connectorStatus = stationInfo?.Connectors[templateConnectorId]; ChargingStationUtils.checkStationInfoConnectorStatus( templateConnectorId, @@ -1309,12 +1367,9 @@ export class ChargingStation { this.templateFile ); this.connectors.set(connectorId, Utils.cloneObject(connectorStatus)); - this.getConnectorStatus(connectorId).availability = AvailabilityType.Operative; - if (Utils.isUndefined(this.getConnectorStatus(connectorId)?.chargingProfiles)) { - this.getConnectorStatus(connectorId).chargingProfiles = []; - } - ChargingStationUtils.initializeConnectorsMapStatus(this.connectors, this.logPrefix()); } + ChargingStationUtils.initializeConnectorsMapStatus(this.connectors, this.logPrefix()); + this.saveConnectorsStatus(); } else { logger.warn( `${this.logPrefix()} Charging station information from template ${ @@ -1345,6 +1400,13 @@ export class ChargingStation { } with no evse id 0 configuration` ); } + if (!stationInfo?.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) { const evsesConfigHash = crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) @@ -1358,7 +1420,8 @@ export class ChargingStation { const templateMaxEvses = ChargingStationUtils.getMaxNumberOfEvses(stationInfo?.Evses); if (templateMaxEvses > 0) { for (const evse in stationInfo.Evses) { - this.evses.set(Utils.convertToInt(evse), { + const evseId = Utils.convertToInt(evse); + this.evses.set(evseId, { connectors: ChargingStationUtils.buildConnectorsMap( stationInfo?.Evses[evse]?.Connectors, this.logPrefix(), @@ -1367,10 +1430,11 @@ export class ChargingStation { availability: AvailabilityType.Operative, }); ChargingStationUtils.initializeConnectorsMapStatus( - this.evses.get(Utils.convertToInt(evse))?.connectors, + this.evses.get(evseId)?.connectors, this.logPrefix() ); } + this.saveEvsesStatus(); } else { logger.warn( `${this.logPrefix()} Charging station information from template ${ @@ -1378,13 +1442,13 @@ export class ChargingStation { } with no evses configuration defined, cannot create evses` ); } - } else { - logger.warn( - `${this.logPrefix()} Charging station information from template ${ - this.templateFile - } with no evses configuration defined, using already defined evses` - ); } + } else { + logger.warn( + `${this.logPrefix()} Charging station information from template ${ + this.templateFile + } with no evses configuration defined, using already defined evses` + ); } } @@ -1418,17 +1482,62 @@ export class ChargingStation { return configuration; } - private saveConfiguration(): void { + private saveConnectorsStatus() { + if (this.getOcppPersistentConfiguration()) { + this.saveConfiguration({ stationInfo: false, ocppConfiguration: false, evses: false }); + } + } + + private saveEvsesStatus() { + if (this.getOcppPersistentConfiguration()) { + this.saveConfiguration({ stationInfo: false, ocppConfiguration: false, connectors: false }); + } + } + + private saveConfiguration( + params: { + stationInfo?: boolean; + ocppConfiguration?: boolean; + connectors?: boolean; + evses?: boolean; + } = { stationInfo: true, ocppConfiguration: true, connectors: true, evses: true } + ): void { if (this.configurationFile) { + params = { + ...params, + ...{ stationInfo: true, ocppConfiguration: true, connectors: true, evses: true }, + }; 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); + if (params.stationInfo && this.stationInfo) { + configurationData.stationInfo = this.stationInfo; + } + if (params.ocppConfiguration && this.ocppConfiguration?.configurationKey) { + configurationData.configurationKey = this.ocppConfiguration.configurationKey; + } + if (params.connectors && this.connectors.size > 0) { + configurationData.connectorsStatus = [...this.connectors.values()].map( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest + ); + } + if (params.evses && this.evses.size > 0) { + configurationData.evsesStatus = [...this.evses.values()].map((evseStatus) => { + const status = { + ...evseStatus, + connectorsStatus: [...evseStatus.connectors.values()].map( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest + ), + }; + delete status.connectors; + return status as EvseStatusConfiguration; + }); + } delete configurationData.configurationHash; const configurationHash = crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) @@ -1758,18 +1867,38 @@ export class ChargingStation { private getNumberOfRunningTransactions(): number { let trxCount = 0; - for (const connectorId of this.connectors.keys()) { - if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) { - trxCount++; + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + for (const connectorStatus of evseStatus.connectors.values()) { + if (connectorStatus.transactionStarted === true) { + trxCount++; + } + } + } + } else { + for (const connectorId of this.connectors.keys()) { + if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) { + trxCount++; + } } } return trxCount; } private async stopRunningTransactions(reason = StopTransactionReason.NONE): Promise { - for (const connectorId of this.connectors.keys()) { - if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) { - await this.stopTransactionOnConnector(connectorId, reason); + if (this.hasEvses) { + for (const evseStatus of this.evses.values()) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + if (connectorStatus.transactionStarted === true) { + await this.stopTransactionOnConnector(connectorId, reason); + } + } + } + } else { + for (const connectorId of this.connectors.keys()) { + if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) { + await this.stopTransactionOnConnector(connectorId, reason); + } } } }