X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=7df0a35ff7486bb7282455b4c3d63f629bbf7d99;hb=48847bc0d5e594c3e4c0b81c580ac6df48052668;hp=5e3771f67324cacc6a1f0851ab0ae2c9bed42ec5;hpb=ae61fa2feb89927b7d56ffdc7a54f4dff6b662b4;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 5e3771f6..7df0a35f 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -1,6 +1,6 @@ // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved. -import { createHash } from 'node:crypto' +import { createHash, randomInt } from 'node:crypto' import { EventEmitter } from 'node:events' import { existsSync, type FSWatcher, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { dirname, join } from 'node:path' @@ -88,7 +88,6 @@ import { exponentialDelay, formatDurationMilliSeconds, formatDurationSeconds, - getRandomInteger, getWebSocketCloseEventStatusString, handleFileException, isNotEmptyArray, @@ -229,7 +228,7 @@ export class ChargingStation extends EventEmitter { this.wsConnectionRetried ? true : this.getAutomaticTransactionGeneratorConfiguration()?.stopAbsoluteDuration - ).catch(error => { + ).catch((error: unknown) => { logger.error(`${this.logPrefix()} Error while starting the message sequence:`, error) }) this.wsConnectionRetried = false @@ -262,14 +261,17 @@ export class ChargingStation extends EventEmitter { } public get wsConnectionUrl (): URL { + const wsConnectionBaseUrlStr = `${ + this.stationInfo?.supervisionUrlOcppConfiguration === true && + isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) && + isNotEmptyString(getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value) + ? getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value + : this.configuredSupervisionUrl.href + }` return new URL( - `${ - this.stationInfo?.supervisionUrlOcppConfiguration === true && - isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) && - isNotEmptyString(getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value) - ? getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value - : this.configuredSupervisionUrl.href - }/${this.stationInfo?.chargingStationId}` + `${wsConnectionBaseUrlStr}${ + !wsConnectionBaseUrlStr.endsWith('/') ? '/' : '' + }${this.stationInfo?.chargingStationId}` ) } @@ -287,7 +289,7 @@ export class ChargingStation extends EventEmitter { readFileSync(this.templateFile, 'utf8') ) as ChargingStationTemplate } catch { - stationTemplate = undefined + // Ignore } return logPrefix(` ${getChargingStationId(this.index, stationTemplate)} |`) } @@ -411,14 +413,17 @@ export class ChargingStation extends EventEmitter { const connectorChargingProfilesPowerLimit = getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId) return min( - isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower, + isNaN(connectorMaximumPower) ? Number.POSITIVE_INFINITY : connectorMaximumPower, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion isNaN(connectorAmperageLimitationPowerLimit!) - ? Infinity + ? Number.POSITIVE_INFINITY : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion connectorAmperageLimitationPowerLimit!, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - isNaN(connectorChargingProfilesPowerLimit!) ? Infinity : connectorChargingProfilesPowerLimit! + isNaN(connectorChargingProfilesPowerLimit!) + ? Number.POSITIVE_INFINITY + : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + connectorChargingProfilesPowerLimit! ) } @@ -553,7 +558,7 @@ export class ChargingStation extends EventEmitter { this.heartbeatSetInterval = setInterval(() => { this.ocppRequestService .requestHandler(this, RequestCommand.HEARTBEAT) - .catch(error => { + .catch((error: unknown) => { logger.error( `${this.logPrefix()} Error while sending '${RequestCommand.HEARTBEAT}':`, error @@ -638,7 +643,7 @@ export class ChargingStation extends EventEmitter { meterValue: [meterValue] } ) - .catch(error => { + .catch((error: unknown) => { logger.error( `${this.logPrefix()} Error while sending '${RequestCommand.METER_VALUES}':`, error @@ -842,7 +847,7 @@ export class ChargingStation extends EventEmitter { this.wsConnection.on('close', this.onClose.bind(this)) // Handle WebSocket open this.wsConnection.on('open', () => { - this.onOpen().catch(error => + this.onOpen().catch((error: unknown) => logger.error(`${this.logPrefix()} Error while opening WebSocket connection:`, error) ) }) @@ -944,7 +949,7 @@ export class ChargingStation extends EventEmitter { ) } return await this.ocppRequestService.requestHandler< - StopTransactionRequest, + Partial, StopTransactionResponse >(this, RequestCommand.STOP_TRANSACTION, { transactionId, @@ -1192,15 +1197,6 @@ export class ChargingStation extends EventEmitter { } does not match firmware version pattern '${stationInfo.firmwareVersionPattern}'` ) } - stationInfo.firmwareUpgrade = mergeDeepRight( - { - versionUpgrade: { - step: 1 - }, - reset: true - }, - stationTemplate.firmwareUpgrade ?? {} - ) if (stationTemplate.resetTime != null) { stationInfo.resetTime = secondsToMilliseconds(stationTemplate.resetTime) } @@ -1237,6 +1233,7 @@ export class ChargingStation extends EventEmitter { const stationInfoFromFile = this.getStationInfoFromFile( stationInfoFromTemplate.stationInfoPersistentConfiguration ) + let stationInfo: ChargingStationInfo // Priority: // 1. charging station info from template // 2. charging station info from configuration file @@ -1244,19 +1241,14 @@ export class ChargingStation extends EventEmitter { stationInfoFromFile != null && stationInfoFromFile.templateHash === stationInfoFromTemplate.templateHash ) { - return setChargingStationOptions( - { ...Constants.DEFAULT_STATION_INFO, ...stationInfoFromFile }, - options - ) + stationInfo = stationInfoFromFile + } else { + stationInfo = stationInfoFromTemplate + stationInfoFromFile != null && + propagateSerialNumber(this.getTemplateFromFile(), stationInfoFromFile, stationInfo) } - stationInfoFromFile != null && - propagateSerialNumber( - this.getTemplateFromFile(), - stationInfoFromFile, - stationInfoFromTemplate - ) return setChargingStationOptions( - { ...Constants.DEFAULT_STATION_INFO, ...stationInfoFromTemplate }, + mergeDeepRight(Constants.DEFAULT_STATION_INFO, stationInfo), options ) } @@ -1372,7 +1364,9 @@ export class ChargingStation extends EventEmitter { addConfigurationKey(this, StandardParametersKey.HeartbeatInterval, '0') } if (getConfigurationKey(this, StandardParametersKey.HeartBeatInterval) == null) { - addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', { visible: false }) + addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', { + visible: false + }) } if ( this.stationInfo?.supervisionUrlOcppConfiguration === true && @@ -1390,7 +1384,9 @@ export class ChargingStation extends EventEmitter { isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) && getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey) != null ) { - deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, { save: false }) + deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, { + save: false + }) } if ( isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) && @@ -1554,7 +1550,7 @@ export class ChargingStation extends EventEmitter { } const templateConnectorId = connectorId > 0 && stationTemplate.randomConnectors === true - ? getRandomInteger(templateMaxAvailableConnectors, 1) + ? randomInt(1, templateMaxAvailableConnectors) : connectorId const connectorStatus = stationTemplate.Connectors[templateConnectorId] checkStationInfoConnectorStatus( @@ -1749,7 +1745,9 @@ export class ChargingStation extends EventEmitter { ...(this.connectors.size > 0 && { connectorsStatus: configurationData.connectorsStatus }), - ...(this.evses.size > 0 && { evsesStatus: configurationData.evsesStatus }) + ...(this.evses.size > 0 && { + evsesStatus: configurationData.evsesStatus + }) } satisfies ChargingStationConfiguration) ) .digest('hex') @@ -1767,7 +1765,7 @@ export class ChargingStation extends EventEmitter { this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash) this.sharedLRUCache.setChargingStationConfiguration(configurationData) this.configurationFileHash = configurationHash - }).catch(error => { + }).catch((error: unknown) => { handleFileException( this.configurationFile, FileType.ChargingStationConfiguration, @@ -1826,7 +1824,9 @@ export class ChargingStation extends EventEmitter { if (this.isWebSocketConnectionOpened()) { this.emit(ChargingStationEvents.updated) logger.info( - `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.href} succeeded` + `${this.logPrefix()} Connection to OCPP server through ${ + this.wsConnectionUrl.href + } succeeded` ) let registrationRetryCount = 0 if (!this.isRegistered()) { @@ -1911,7 +1911,9 @@ export class ChargingStation extends EventEmitter { .then(() => { this.emit(ChargingStationEvents.updated) }) - .catch(error => logger.error(`${this.logPrefix()} Error while reconnecting:`, error)) + .catch((error: unknown) => + logger.error(`${this.logPrefix()} Error while reconnecting:`, error) + ) break } } @@ -2083,7 +2085,9 @@ export class ChargingStation extends EventEmitter { // eslint-disable-next-line @typescript-eslint/no-base-to-string }' message '${data.toString()}'${ this.requests.has(messageId) - ? ` matching cached request '${JSON.stringify(this.getCachedRequest(messageType, messageId))}'` + ? ` matching cached request '${JSON.stringify( + this.getCachedRequest(messageType, messageId) + )}'` : '' } processing error:`, error @@ -2233,21 +2237,28 @@ export class ChargingStation extends EventEmitter { for (const [evseId, evseStatus] of this.evses) { if (evseId > 0) { for (const [connectorId, connectorStatus] of evseStatus.connectors) { - const connectorBootStatus = getBootConnectorStatus(this, connectorId, connectorStatus) - await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus, evseId) + await sendAndSetConnectorStatus( + this, + connectorId, + getBootConnectorStatus(this, connectorId, connectorStatus), + evseId + ) } } } } else { for (const connectorId of this.connectors.keys()) { if (connectorId > 0) { - const connectorBootStatus = getBootConnectorStatus( + await sendAndSetConnectorStatus( this, connectorId, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.getConnectorStatus(connectorId)! + getBootConnectorStatus( + this, + connectorId, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.getConnectorStatus(connectorId)! + ) ) - await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus) } } } @@ -2366,9 +2377,9 @@ export class ChargingStation extends EventEmitter { ) && logger.warn( // eslint-disable-next-line @typescript-eslint/no-base-to-string - `${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' in configuration from values '${SupervisionUrlDistribution.toString()}', defaulting to ${ + `${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' in configuration from values '${SupervisionUrlDistribution.toString()}', defaulting to '${ SupervisionUrlDistribution.CHARGING_STATION_AFFINITY - }` + }'` ) configuredSupervisionUrlIndex = (this.index - 1) % supervisionUrls.length break