From b72d174972edbd0572e0489036924934e6d8ea1c Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 8 Apr 2025 11:22:10 +0200 Subject: [PATCH] fix: ensure CS in pending state can send boot notification (#1376) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * fix: ensure CS in pending state can send boot notification closes #1374 Signed-off-by: Jérôme Benoit * fix: proper CS state conditions Signed-off-by: Jérôme Benoit --------- Signed-off-by: Jérôme Benoit --- src/charging-station/ChargingStation.ts | 33 +++++++------- .../ocpp/1.6/OCPP16IncomingRequestService.ts | 3 +- .../ocpp/1.6/OCPP16ResponseService.ts | 45 ++++++++++--------- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 3 +- .../ocpp/2.0/OCPP20ResponseService.ts | 31 +++++++------ .../ocpp/OCPPRequestService.ts | 5 ++- src/types/ChargingStationEvents.ts | 2 +- 7 files changed, 67 insertions(+), 55 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index f2f8bc2d..8a66d31a 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -646,10 +646,6 @@ export class ChargingStation extends EventEmitter { return false } - public isRegistered (): boolean { - return !this.inUnknownState() && (this.inAcceptedState() || this.inPendingState()) - } - public isWebSocketConnectionOpened (): boolean { return this.wsConnection?.readyState === WebSocket.OPEN } @@ -2087,7 +2083,7 @@ export class ChargingStation extends EventEmitter { } succeeded` ) let registrationRetryCount = 0 - if (!this.isRegistered()) { + if (!this.inAcceptedState()) { // Send BootNotification do { await this.ocppRequestService.requestHandler< @@ -2100,22 +2096,25 @@ export class ChargingStation extends EventEmitter { this.bootNotificationResponse!.currentTime = convertToDate( this.bootNotificationResponse?.currentTime )! - if (!this.isRegistered()) { - this.stationInfo?.registrationMaxRetries !== -1 && ++registrationRetryCount + if (!this.inAcceptedState()) { + ++registrationRetryCount await sleep( - this.bootNotificationResponse?.interval != null - ? secondsToMilliseconds(this.bootNotificationResponse.interval) - : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL + exponentialDelay( + registrationRetryCount, + this.bootNotificationResponse?.interval != null + ? secondsToMilliseconds(this.bootNotificationResponse.interval) + : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL + ) ) } } while ( - !this.isRegistered() && - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (registrationRetryCount <= this.stationInfo!.registrationMaxRetries! || - this.stationInfo?.registrationMaxRetries === -1) + !this.inAcceptedState() && + (this.stationInfo?.registrationMaxRetries === -1 || + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + registrationRetryCount <= this.stationInfo!.registrationMaxRetries!) ) } - if (!this.isRegistered()) { + if (!this.inAcceptedState()) { logger.error( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount.toString()}) or retry disabled (${this.stationInfo?.registrationMaxRetries?.toString()})` @@ -2139,9 +2138,9 @@ export class ChargingStation extends EventEmitter { private async reconnect (): Promise { if ( + this.stationInfo?.autoReconnectMaxRetries === -1 || // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.wsConnectionRetryCount < this.stationInfo!.autoReconnectMaxRetries! || - this.stationInfo?.autoReconnectMaxRetries === -1 + this.wsConnectionRetryCount < this.stationInfo!.autoReconnectMaxRetries! ) { ++this.wsConnectionRetryCount const reconnectDelay = diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 91b45b13..6ecf4fe8 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -597,7 +597,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ) } if ( - chargingStation.isRegistered() || + chargingStation.inAcceptedState() || + chargingStation.inPendingState() || (chargingStation.stationInfo?.ocppStrictCompliance === false && chargingStation.inUnknownState()) ) { diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index bac3f9fa..3666d048 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -386,7 +386,13 @@ export class OCPP16ResponseService extends OCPPResponseService { payload: ResType, requestPayload: ReqType ): Promise { - if (chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) { + if ( + chargingStation.inAcceptedState() || + ((chargingStation.inUnknownState() || chargingStation.inPendingState()) && + commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) || + (chargingStation.stationInfo?.ocppStrictCompliance === false && + (chargingStation.inUnknownState() || chargingStation.inPendingState())) + ) { if ( this.responseHandlers.has(commandName) && OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) @@ -502,25 +508,24 @@ export class OCPP16ResponseService extends OCPPResponseService { ): void { if (Object.values(RegistrationStatusEnumType).includes(payload.status)) { chargingStation.bootNotificationResponse = payload - if (chargingStation.isRegistered()) { - chargingStation.emit(ChargingStationEvents.registered) - if (chargingStation.inAcceptedState()) { - addConfigurationKey( - chargingStation, - OCPP16StandardParametersKey.HeartbeatInterval, - payload.interval.toString(), - {}, - { overwrite: true, save: true } - ) - addConfigurationKey( - chargingStation, - OCPP16StandardParametersKey.HeartBeatInterval, - payload.interval.toString(), - { visible: false }, - { overwrite: true, save: true } - ) - chargingStation.emit(ChargingStationEvents.accepted) - } + if (chargingStation.inAcceptedState()) { + addConfigurationKey( + chargingStation, + OCPP16StandardParametersKey.HeartbeatInterval, + payload.interval.toString(), + {}, + { overwrite: true, save: true } + ) + addConfigurationKey( + chargingStation, + OCPP16StandardParametersKey.HeartBeatInterval, + payload.interval.toString(), + { visible: false }, + { overwrite: true, save: true } + ) + chargingStation.emit(ChargingStationEvents.accepted) + } else if (chargingStation.inPendingState()) { + chargingStation.emit(ChargingStationEvents.pending) } else if (chargingStation.inRejectedState()) { chargingStation.emit(ChargingStationEvents.rejected) } diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index 39075970..3be92e9e 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -79,7 +79,8 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { ) } if ( - chargingStation.isRegistered() || + chargingStation.inAcceptedState() || + chargingStation.inPendingState() || (chargingStation.stationInfo?.ocppStrictCompliance === false && chargingStation.inUnknownState()) ) { diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index 0b0c32a7..be63f14a 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -104,7 +104,13 @@ export class OCPP20ResponseService extends OCPPResponseService { payload: ResType, requestPayload: ReqType ): Promise { - if (chargingStation.isRegistered() || commandName === OCPP20RequestCommand.BOOT_NOTIFICATION) { + if ( + chargingStation.inAcceptedState() || + ((chargingStation.inUnknownState() || chargingStation.inPendingState()) && + commandName === OCPP20RequestCommand.BOOT_NOTIFICATION) || + (chargingStation.stationInfo?.ocppStrictCompliance === false && + (chargingStation.inUnknownState() || chargingStation.inPendingState())) + ) { if ( this.responseHandlers.has(commandName) && OCPP20ServiceUtils.isRequestCommandSupported(chargingStation, commandName) @@ -164,18 +170,17 @@ export class OCPP20ResponseService extends OCPPResponseService { ): void { if (Object.values(RegistrationStatusEnumType).includes(payload.status)) { chargingStation.bootNotificationResponse = payload - if (chargingStation.isRegistered()) { - chargingStation.emit(ChargingStationEvents.registered) - if (chargingStation.inAcceptedState()) { - addConfigurationKey( - chargingStation, - OCPP20OptionalVariableName.HeartbeatInterval, - payload.interval.toString(), - {}, - { overwrite: true, save: true } - ) - chargingStation.emit(ChargingStationEvents.accepted) - } + if (chargingStation.inAcceptedState()) { + addConfigurationKey( + chargingStation, + OCPP20OptionalVariableName.HeartbeatInterval, + payload.interval.toString(), + {}, + { overwrite: true, save: true } + ) + chargingStation.emit(ChargingStationEvents.accepted) + } else if (chargingStation.inPendingState()) { + chargingStation.emit(ChargingStationEvents.pending) } else if (chargingStation.inRejectedState()) { chargingStation.emit(ChargingStationEvents.rejected) } diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 88f03de9..d847a6e8 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -243,9 +243,10 @@ export abstract class OCPPRequestService { ...params, } if ( - (chargingStation.inUnknownState() && commandName === RequestCommand.BOOT_NOTIFICATION) || + ((chargingStation.inUnknownState() || chargingStation.inPendingState()) && + commandName === RequestCommand.BOOT_NOTIFICATION) || (chargingStation.stationInfo?.ocppStrictCompliance === false && - chargingStation.inUnknownState()) || + (chargingStation.inUnknownState() || chargingStation.inPendingState())) || chargingStation.inAcceptedState() || (chargingStation.inPendingState() && (params.triggerMessage === true || messageType === MessageType.CALL_RESULT_MESSAGE)) diff --git a/src/types/ChargingStationEvents.ts b/src/types/ChargingStationEvents.ts index b1d27038..305b84a8 100644 --- a/src/types/ChargingStationEvents.ts +++ b/src/types/ChargingStationEvents.ts @@ -5,7 +5,7 @@ export enum ChargingStationEvents { connectorStatusChanged = 'connectorStatusChanged', deleted = 'deleted', disconnected = 'disconnected', - registered = 'registered', + pending = 'pending', rejected = 'rejected', started = 'started', stopped = 'stopped', -- 2.43.0