X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=018a6fbeea98fa780b522a2d08c1218011aa6c7f;hb=16cd35ad01b48377d39077d8b30e6c2055a5f8ea;hp=ad4dac388a293b56243982184dd1f40848b7fbf3;hpb=057e2042576fb5f4dd4c201f1bd0f64c35ccf961;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index ad4dac38..018a6fbe 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -31,6 +31,7 @@ import { OCPPVersion } from '../types/ocpp/OCPPVersion'; import PerformanceStatistics from '../performance/PerformanceStatistics'; import { SampledValueTemplate } from '../types/MeasurandPerPhaseSampledValueTemplates'; import { StopTransactionReason } from '../types/ocpp/Transaction'; +import { SupervisionUrlDistribution } from '../types/ConfigurationData'; import { URL } from 'url'; import Utils from '../utils/Utils'; import crypto from 'crypto'; @@ -121,10 +122,22 @@ export default class ChargingStation { return this?.wsConnection?.readyState === OPEN; } - public isRegistered(): boolean { + public isInPendingState(): boolean { + return this?.bootNotificationResponse?.status === RegistrationStatus.PENDING; + } + + public isInAcceptedState(): boolean { return this?.bootNotificationResponse?.status === RegistrationStatus.ACCEPTED; } + public isInRejectedState(): boolean { + return this?.bootNotificationResponse?.status === RegistrationStatus.REJECTED; + } + + public isRegistered(): boolean { + return this.isInAcceptedState() || this.isInPendingState(); + } + public isChargingStationAvailable(): boolean { return this.getConnectorStatus(0).availability === AvailabilityType.OPERATIVE; } @@ -461,6 +474,10 @@ export default class ChargingStation { } catch (error) { FileUtils.handleFileException(this.logPrefix(), 'Template', this.stationTemplateFile, error as NodeJS.ErrnoException); } + const chargingStationId = this.getChargingStationId(stationTemplateFromFile); + // Deprecation template keys section + this.warnDeprecatedTemplateKey(stationTemplateFromFile, 'supervisionUrl', chargingStationId, 'Use \'supervisionUrls\' instead'); + this.convertDeprecatedTemplateKey(stationTemplateFromFile, 'supervisionUrl', 'supervisionUrls'); const stationInfo: ChargingStationInfo = stationTemplateFromFile ?? {} as ChargingStationInfo; stationInfo.wsOptions = stationTemplateFromFile?.wsOptions ?? {}; if (!Utils.isEmptyArray(stationTemplateFromFile.power)) { @@ -477,7 +494,7 @@ export default class ChargingStation { } delete stationInfo.power; delete stationInfo.powerUnit; - stationInfo.chargingStationId = this.getChargingStationId(stationTemplateFromFile); + stationInfo.chargingStationId = chargingStationId; stationInfo.resetTime = stationTemplateFromFile.resetTime ? stationTemplateFromFile.resetTime * 1000 : Constants.CHARGING_STATION_DEFAULT_RESET_TIME; return stationInfo; } @@ -639,12 +656,22 @@ export default class ChargingStation { await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel, this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion); } - if (this.isRegistered()) { + if (this.isInAcceptedState()) { await this.startMessageSequence(); this.stopped && (this.stopped = false); if (this.wsConnectionRestarted && this.isWebSocketConnectionOpened()) { this.flushMessageBuffer(); } + } else if (this.isInPendingState()) { + // The central server shall issue a triggerMessage to the charging station for the boot notification at the end of its configuration process + while (!this.isInAcceptedState()) { + await this.startMessageSequence(); + this.stopped && (this.stopped = false); + if (this.wsConnectionRestarted && this.isWebSocketConnectionOpened()) { + this.flushMessageBuffer(); + } + await Utils.sleep(Constants.CHARGING_STATION_DEFAULT_START_SEQUENCE_DELAY); + } } else { logger.error(`${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`); } @@ -933,17 +960,45 @@ export default class ChargingStation { } } + private warnDeprecatedTemplateKey(template: ChargingStationTemplate, key: string, chargingStationId: string, logMsgToAppend = ''): void { + if (!Utils.isUndefined(template[key])) { + logger.warn(`${Utils.logPrefix(` ${chargingStationId} |`)} Deprecated template key '${key}' usage in file '${this.stationTemplateFile}'${logMsgToAppend && '. ' + logMsgToAppend}`); + } + } + + private convertDeprecatedTemplateKey(template: ChargingStationTemplate, deprecatedKey: string, key: string): void { + if (!Utils.isUndefined(template[deprecatedKey])) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + template[key] = template[deprecatedKey]; + delete template[deprecatedKey]; + } + } + private getConfiguredSupervisionUrl(): URL { - const supervisionUrls = Utils.cloneObject(this.stationInfo.supervisionUrl ?? Configuration.getSupervisionUrls()); - let indexUrl = 0; + const supervisionUrls = Utils.cloneObject(this.stationInfo.supervisionUrls ?? Configuration.getSupervisionUrls()); if (!Utils.isEmptyArray(supervisionUrls)) { - if (Configuration.getDistributeStationsToTenantsEqually()) { - indexUrl = this.index % supervisionUrls.length; - } else { - // Get a random url - indexUrl = Math.floor(Utils.secureRandom() * supervisionUrls.length); + let urlIndex = 0; + switch (Configuration.getSupervisionUrlDistribution()) { + case SupervisionUrlDistribution.ROUND_ROBIN: + urlIndex = (this.index - 1) % supervisionUrls.length; + break; + case SupervisionUrlDistribution.RANDOM: + // Get a random url + urlIndex = Math.floor(Utils.secureRandom() * supervisionUrls.length); + break; + case SupervisionUrlDistribution.SEQUENTIAL: + if (this.index <= supervisionUrls.length) { + urlIndex = this.index - 1; + } else { + logger.warn(`${this.logPrefix()} No more configured supervision urls available, using the first one`); + } + break; + default: + logger.error(`${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${SupervisionUrlDistribution.ROUND_ROBIN}`); + urlIndex = (this.index - 1) % supervisionUrls.length; + break; } - return new URL(supervisionUrls[indexUrl]); + return new URL(supervisionUrls[urlIndex]); } return new URL(supervisionUrls as string); }