From 52952bf8f73e5ad1a85c0c9205412a9198bfc720 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 28 Apr 2023 12:10:54 +0200 Subject: [PATCH] feat: save connectors/evses map in charging station configuration file MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reference: https://github.com/SAP/e-mobility-charging-stations-simulator/issues/505 Signed-off-by: Jérôme Benoit --- src/charging-station/ChargingStation.ts | 71 ++++++++++++++++---- src/charging-station/ChargingStationUtils.ts | 34 ++++++---- src/charging-station/MessageChannelUtils.ts | 9 +++ src/types/ChargingStationConfiguration.ts | 18 ++++- src/types/ChargingStationWorker.ts | 6 ++ src/types/index.ts | 1 + ui/web/.vscode/settings.json | 2 + ui/web/src/types/ChargingStationType.ts | 14 ++-- 8 files changed, 124 insertions(+), 31 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 928a8317..0d7f2865 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, @@ -679,7 +680,7 @@ export class ChargingStation { public saveOcppConfiguration(): void { if (this.getOcppPersistentConfiguration()) { - this.saveConfiguration(); + this.saveConfiguration({ stationInfo: false, connectors: false, evses: false }); } } @@ -1000,7 +1001,7 @@ export class ChargingStation { private saveStationInfo(): void { if (this.getStationInfoPersistentConfiguration()) { - this.saveConfiguration(); + this.saveConfiguration({ ocppConfiguration: false, connectors: false, evses: false }); } } @@ -1375,12 +1376,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 ${ @@ -1431,7 +1429,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(), @@ -1440,10 +1439,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 ${ @@ -1491,17 +1491,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) diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index c5c42f02..9f93e5ff 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -194,10 +194,6 @@ export class ChargingStationUtils { templateFile ); connectorsMap.set(connectorId, Utils.cloneObject(connectorStatus)); - connectorsMap.get(connectorId).availability = AvailabilityType.Operative; - if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) { - connectorsMap.get(connectorId).chargingProfiles = []; - } } } else { logger.warn( @@ -220,6 +216,14 @@ export class ChargingStationUtils { ); } if ( + connectorId === 0 && + Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted) + ) { + connectors.get(connectorId).availability = AvailabilityType.Operative; + if (Utils.isUndefined(connectors.get(connectorId)?.chargingProfiles)) { + connectors.get(connectorId).chargingProfiles = []; + } + } else if ( connectorId > 0 && Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted) ) { @@ -228,15 +232,6 @@ export class ChargingStationUtils { } } - public static initializeConnectorStatus(connectorStatus: ConnectorStatus): void { - connectorStatus.idTagLocalAuthorized = false; - connectorStatus.idTagAuthorized = false; - connectorStatus.transactionRemoteStarted = false; - connectorStatus.transactionStarted = false; - connectorStatus.energyActiveImportRegisterValue = 0; - connectorStatus.transactionEnergyActiveImportRegisterValue = 0; - } - public static resetConnectorStatus(connectorStatus: ConnectorStatus): void { connectorStatus.idTagLocalAuthorized = false; connectorStatus.idTagAuthorized = false; @@ -523,6 +518,19 @@ export class ChargingStationUtils { ); } + 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 (Utils.isUndefined(connectorStatus.chargingProfiles)) { + connectorStatus.chargingProfiles = []; + } + } + private static warnDeprecatedTemplateKey( template: ChargingStationTemplate, key: string, diff --git a/src/charging-station/MessageChannelUtils.ts b/src/charging-station/MessageChannelUtils.ts index 446ecfbb..28bfa8c6 100644 --- a/src/charging-station/MessageChannelUtils.ts +++ b/src/charging-station/MessageChannelUtils.ts @@ -57,6 +57,15 @@ export class MessageChannelUtils { // eslint-disable-next-line @typescript-eslint/no-unused-vars ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest ), + evses: [...chargingStation.evses.values()].map((evseStatus) => { + return { + ...evseStatus, + connectors: [...evseStatus.connectors.values()].map( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest + ), + }; + }), ocppConfiguration: chargingStation.ocppConfiguration, wsState: chargingStation?.wsConnection?.readyState, bootNotificationResponse: chargingStation.bootNotificationResponse, diff --git a/src/types/ChargingStationConfiguration.ts b/src/types/ChargingStationConfiguration.ts index 09509038..9f0d3423 100644 --- a/src/types/ChargingStationConfiguration.ts +++ b/src/types/ChargingStationConfiguration.ts @@ -2,10 +2,26 @@ import type { ChargingStationAutomaticTransactionGeneratorConfiguration, ChargingStationInfoConfiguration, ChargingStationOcppConfiguration, + ConnectorStatus, + EvseStatus, } from './internal'; +type ConnectorsConfiguration = { + connectorsStatus?: ConnectorStatus[]; +}; + +export type EvseStatusConfiguration = Omit & { + connectorsStatus?: ConnectorStatus[]; +}; + +type EvsesConfiguration = { + evsesStatus?: EvseStatusConfiguration[]; +}; + export type ChargingStationConfiguration = ChargingStationInfoConfiguration & ChargingStationOcppConfiguration & - ChargingStationAutomaticTransactionGeneratorConfiguration & { + ChargingStationAutomaticTransactionGeneratorConfiguration & + ConnectorsConfiguration & + EvsesConfiguration & { configurationHash?: string; }; diff --git a/src/types/ChargingStationWorker.ts b/src/types/ChargingStationWorker.ts index 7578b217..3164414a 100644 --- a/src/types/ChargingStationWorker.ts +++ b/src/types/ChargingStationWorker.ts @@ -6,6 +6,7 @@ import type { ChargingStationInfo, ChargingStationOcppConfiguration, ConnectorStatus, + EvseStatus, JsonObject, Statistics, } from './internal'; @@ -21,10 +22,15 @@ export interface ChargingStationWorkerData extends WorkerData { chargingStationWorkerOptions?: ChargingStationWorkerOptions; } +type EvseStatusType = Omit & { + connectors?: ConnectorStatus[]; +}; + export interface ChargingStationData extends WorkerData { started: boolean; stationInfo: ChargingStationInfo; connectors: ConnectorStatus[]; + evses: EvseStatusType[]; ocppConfiguration: ChargingStationOcppConfiguration; wsState?: | typeof WebSocket.CONNECTING diff --git a/src/types/index.ts b/src/types/index.ts index 1a349c3a..b750cf35 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -60,6 +60,7 @@ export { type ErrorResponse, ErrorType, type EvseStatus, + type EvseStatusConfiguration, type EvseTemplate, FileType, FirmwareStatus, diff --git a/ui/web/.vscode/settings.json b/ui/web/.vscode/settings.json index f7432095..291c11c1 100644 --- a/ui/web/.vscode/settings.json +++ b/ui/web/.vscode/settings.json @@ -5,6 +5,8 @@ "cSpell.words": [ "Avenir", "composables", + "evse", + "evses", "finalhandler", "iccid", "idtag", diff --git a/ui/web/src/types/ChargingStationType.ts b/ui/web/src/types/ChargingStationType.ts index 9d2b530a..e9f5f108 100644 --- a/ui/web/src/types/ChargingStationType.ts +++ b/ui/web/src/types/ChargingStationType.ts @@ -1,16 +1,17 @@ import type { JsonObject } from './JsonType'; export type ChargingStationData = { - stationInfo: ChargingStationInfo; started: boolean; + stationInfo: ChargingStationInfo; + connectors: ConnectorStatus[]; + evses: EvseStatus[]; wsState?: | typeof WebSocket.CONNECTING | typeof WebSocket.OPEN | typeof WebSocket.CLOSING | typeof WebSocket.CLOSED; - bootNotificationResponse: BootNotificationResponse; - connectors: ConnectorStatus[]; - automaticTransactionGeneratorStatuses?: Status[]; + bootNotificationResponse?: BootNotificationResponse; + automaticTransactionGenerator?: Status[]; }; export type ChargingStationInfo = { @@ -184,6 +185,11 @@ export type ConnectorStatus = { transactionEnergyActiveImportRegisterValue?: number; // In Wh }; +export type EvseStatus = { + availability: AvailabilityType; + connectors?: ConnectorStatus[]; +}; + export type AvailabilityType = OCPP16AvailabilityType; export enum OCPP16AvailabilityType { -- 2.34.1