From a78ef5ed1052d9cc77435e2dce4aea89442824ee Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Wed, 26 Apr 2023 22:35:43 +0200 Subject: [PATCH] feat: make evse and connector configurations in template mutually exclusive MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Evse configurations is still not use at that stage Reference: https://github.com/SAP/e-mobility-charging-stations-simulator/issues/349 Signed-off-by: Jérôme Benoit --- src/charging-station/ChargingStation.ts | 134 ++++++++++++------- src/charging-station/ChargingStationUtils.ts | 24 +++- src/types/ChargingStationTemplate.ts | 4 +- src/types/Evse.ts | 10 ++ src/types/EvseStatus.ts | 6 - src/types/internal.ts | 2 +- 6 files changed, 117 insertions(+), 63 deletions(-) create mode 100644 src/types/Evse.ts delete mode 100644 src/types/EvseStatus.ts diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 46fae181..96bf6c1b 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -929,28 +929,40 @@ export class ChargingStation { this.templateFile, this.logPrefix() ); - const templateMaxConnectors = - ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate); - ChargingStationUtils.checkTemplateMaxConnectors( - templateMaxConnectors, - this.templateFile, - this.logPrefix() - ); - if ( - configuredMaxConnectors > - (stationTemplate?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) && - !stationTemplate?.randomConnectors - ) { - logger.warn( - `${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${ - this.templateFile - }, forcing random connector configurations affectation` + // Build evses or connectors if needed (FIXME: should be factored out) + if (stationInfo?.Connectors && !stationInfo?.Evses) { + const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors( + stationTemplate.Connectors ); - stationInfo.randomConnectors = true; + ChargingStationUtils.checkTemplateMaxConnectors( + templateMaxConnectors, + this.templateFile, + this.logPrefix() + ); + if ( + configuredMaxConnectors > + (stationTemplate?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) && + !stationTemplate?.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; + } + this.initializeConnectors(stationInfo, configuredMaxConnectors); + } else if (stationInfo?.Evses && !stationInfo?.Connectors) { + this.initializeEvses(stationInfo); + } else if (stationInfo?.Evses && stationInfo?.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); + } else { + const errorMsg = `No connectors or evses defined in template file ${this.templateFile}`; + logger.error(`${this.logPrefix()} ${errorMsg}`); + throw new BaseError(errorMsg); } - // Build connectors if needed (FIXME: should be factored out) - this.initializeConnectors(stationInfo, configuredMaxConnectors, templateMaxConnectors); - this.initializeEvses(stationInfo); stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo); ChargingStationUtils.createStationInfoHash(stationInfo); return stationInfo; @@ -1248,8 +1260,7 @@ export class ChargingStation { private initializeConnectors( stationInfo: ChargingStationInfo, - configuredMaxConnectors: number, - templateMaxConnectors: number + configuredMaxConnectors: number ): void { if (!stationInfo?.Connectors && this.connectors.size === 0) { const logMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`; @@ -1295,6 +1306,9 @@ export class ChargingStation { } } // Generate all connectors + const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors( + stationInfo?.Connectors + ); if ((stationInfo?.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) > 0) { for (let index = 1; index <= configuredMaxConnectors; index++) { const randConnectorId = stationInfo?.randomConnectors @@ -1317,7 +1331,7 @@ export class ChargingStation { } with no connectors configuration defined, using already defined connectors` ); } - // Initialize transaction attributes on connectors + // Initialize connectors status for (const connectorId of this.connectors.keys()) { if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) { logger.warn( @@ -1330,7 +1344,42 @@ export class ChargingStation { connectorId > 0 && Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionStarted) ) { - this.initializeConnectorStatus(connectorId); + this.initializeConnectorStatus(this.getConnectorStatus(connectorId)); + } + } + } + + private buildConnectorsMap( + connectors: Record + ): Map { + const connectorsMap = new Map(); + for (const connector in connectors) { + const connectorStatus = connectors[connector]; + const connectorId = Utils.convertToInt(connector); + this.checkStationInfoConnectorStatus(connectorId, connectorStatus); + connectorsMap.set(connectorId, Utils.cloneObject(connectorStatus)); + connectorsMap.get(connectorId).availability = AvailabilityType.Operative; + if (Utils.isUndefined(connectorsMap.get(connectorId)?.chargingProfiles)) { + connectorsMap.get(connectorId).chargingProfiles = []; + } + } + return connectorsMap; + } + + private initializeConnectorsMapStatus(connectors: Map): 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)); } } } @@ -1359,28 +1408,19 @@ export class ChargingStation { evsesConfigChanged && this.evses.clear(); this.evsesConfigurationHash = evsesConfigHash; for (const evse in stationInfo?.Evses) { - const evseId = Utils.convertToInt(evse); - this.evses.set(evseId, Utils.cloneObject(stationInfo?.Evses[evse])); - this.evses.get(evseId).availability = AvailabilityType.Operative; + 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 { - if (this.connectors.size === 0) { - const logMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no evses configuration defined`; - logger.error(`${this.logPrefix()} ${logMsg}`); - throw new BaseError(logMsg); - } - logger.info( + logger.warn( `${this.logPrefix()} Charging station information from template ${ this.templateFile - } with no evses configuration defined, mapping one connector to one evse` + } with no evses configuration defined, using already defined evses` ); - for (const [connectorId, connectorStatus] of this.connectors) { - this.evses.set(connectorId, { - connectorIds: [connectorId], - availability: connectorStatus.availability, - }); - } } } @@ -2101,12 +2141,12 @@ export class ChargingStation { return this.getTemplateFromFile()?.AutomaticTransactionGenerator; } - private initializeConnectorStatus(connectorId: number): void { - this.getConnectorStatus(connectorId).idTagLocalAuthorized = false; - this.getConnectorStatus(connectorId).idTagAuthorized = false; - this.getConnectorStatus(connectorId).transactionRemoteStarted = false; - this.getConnectorStatus(connectorId).transactionStarted = false; - this.getConnectorStatus(connectorId).energyActiveImportRegisterValue = 0; - this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0; + private initializeConnectorStatus(connectorStatus: ConnectorStatus): void { + connectorStatus.idTagLocalAuthorized = false; + connectorStatus.idTagAuthorized = false; + connectorStatus.transactionRemoteStarted = false; + connectorStatus.transactionStarted = false; + connectorStatus.energyActiveImportRegisterValue = 0; + connectorStatus.transactionEnergyActiveImportRegisterValue = 0; } } diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index bcedfb3a..e2e9821e 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -17,6 +17,7 @@ import { type ChargingSchedulePeriod, type ChargingStationInfo, type ChargingStationTemplate, + type ConnectorStatus, CurrentType, type OCPP16BootNotificationRequest, type OCPP20BootNotificationRequest, @@ -92,12 +93,11 @@ export class ChargingStationUtils { return true; } - public static getTemplateMaxNumberOfConnectors(stationTemplate: ChargingStationTemplate): number { - const templateConnectors = stationTemplate?.Connectors; - if (!templateConnectors) { + public static getMaxNumberOfConnectors(connectors: Record): number { + if (!connectors) { return -1; } - return Object.keys(templateConnectors).length; + return Object.keys(connectors).length; } public static checkTemplateMaxConnectors( @@ -124,10 +124,20 @@ export class ChargingStationUtils { numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)]; } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) { configuredMaxConnectors = stationTemplate.numberOfConnectors as number; - } else { + } else if (stationTemplate.Connectors && !stationTemplate.Evses) { configuredMaxConnectors = stationTemplate?.Connectors[0] - ? ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate) - 1 - : ChargingStationUtils.getTemplateMaxNumberOfConnectors(stationTemplate); + ? 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; } diff --git a/src/types/ChargingStationTemplate.ts b/src/types/ChargingStationTemplate.ts index 4e04c84e..200307ab 100644 --- a/src/types/ChargingStationTemplate.ts +++ b/src/types/ChargingStationTemplate.ts @@ -6,7 +6,7 @@ import type { AutomaticTransactionGeneratorConfiguration, ChargingStationOcppConfiguration, ConnectorStatus, - EvseStatus, + EvseTemplate, FirmwareStatus, IncomingRequestCommand, MessageTrigger, @@ -113,6 +113,6 @@ export type ChargingStationTemplate = { messageTriggerSupport?: Record; Configuration?: ChargingStationOcppConfiguration; AutomaticTransactionGenerator?: AutomaticTransactionGeneratorConfiguration; - Evses?: Record; + Evses?: Record; Connectors: Record; }; diff --git a/src/types/Evse.ts b/src/types/Evse.ts new file mode 100644 index 00000000..275969ba --- /dev/null +++ b/src/types/Evse.ts @@ -0,0 +1,10 @@ +import type { AvailabilityType, ConnectorStatus } from './internal'; + +export type EvseTemplate = { + Connectors: Record; +}; + +export type EvseStatus = { + connectors: Map; + availability: AvailabilityType; +}; diff --git a/src/types/EvseStatus.ts b/src/types/EvseStatus.ts deleted file mode 100644 index f12ff7c6..00000000 --- a/src/types/EvseStatus.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { AvailabilityType } from './internal'; - -export type EvseStatus = { - connectorIds: number[]; - availability: AvailabilityType; -}; diff --git a/src/types/internal.ts b/src/types/internal.ts index 576dca54..86151c8f 100644 --- a/src/types/internal.ts +++ b/src/types/internal.ts @@ -37,7 +37,7 @@ export * from './ChargingStationOcppConfiguration'; export * from './ChargingStationTemplate'; export * from './ChargingStationWorker'; export * from './ConfigurationData'; -export type { EvseStatus } from './EvseStatus'; +export type { EvseTemplate, EvseStatus } from './Evse'; export type { ConnectorStatus } from './ConnectorStatus'; export type { EmptyObject } from './EmptyObject'; export type { HandleErrorParams } from './Error'; -- 2.34.1