From 9ff486f4329a4902e8bcd280c0649a74cb31e4df Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 10 Nov 2023 12:36:58 +0100 Subject: [PATCH] fix: ensure running transactions are stopped at CS stop MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../AutomaticTransactionGenerator.ts | 17 ++++++------ src/charging-station/ChargingStation.ts | 27 ++++++++++--------- .../ChargingStationWorkerBroadcastChannel.ts | 6 ++--- .../ocpp/1.6/OCPP16ResponseService.ts | 4 +-- .../ocpp/1.6/OCPP16ServiceUtils.ts | 2 +- .../ocpp/OCPPIncomingRequestService.ts | 2 +- .../ocpp/OCPPRequestService.ts | 4 +-- .../ocpp/OCPPResponseService.ts | 2 +- src/charging-station/ocpp/OCPPServiceUtils.ts | 24 +++++++++-------- src/types/ocpp/1.6/Transaction.ts | 1 - 10 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index e15ce4ac..38f4901c 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -86,7 +86,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { this.starting = false; } - public async stop(): Promise { + public stop(): void { if (this.started === false) { logger.warn(`${this.logPrefix()} is already stopped`); return; @@ -96,7 +96,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { return; } this.stopping = true; - await this.stopConnectors(); + this.stopConnectors(); this.started = false; this.stopping = false; } @@ -123,14 +123,13 @@ export class AutomaticTransactionGenerator extends AsyncResource { } } - public async stopConnector(connectorId: number): Promise { + public stopConnector(connectorId: number): void { if (this.connectorsStatus.has(connectorId) === false) { logger.error(`${this.logPrefix(connectorId)} stopping on non existing connector`); throw new BaseError(`Connector ${connectorId} does not exist`); } if (this.connectorsStatus.get(connectorId)?.start === true) { this.connectorsStatus.get(connectorId)!.start = false; - await this.stopTransaction(connectorId); } else if (this.connectorsStatus.get(connectorId)?.start === false) { logger.warn(`${this.logPrefix(connectorId)} is already stopped on connector`); } @@ -161,19 +160,19 @@ export class AutomaticTransactionGenerator extends AsyncResource { } } - private async stopConnectors(): Promise { + private stopConnectors(): void { if (this.chargingStation.hasEvses) { for (const [evseId, evseStatus] of this.chargingStation.evses) { if (evseId > 0) { for (const connectorId of evseStatus.connectors.keys()) { - await this.stopConnector(connectorId); + this.stopConnector(connectorId); } } } } else { for (const connectorId of this.chargingStation.connectors.keys()) { if (connectorId > 0) { - await this.stopConnector(connectorId); + this.stopConnector(connectorId); } } } @@ -191,7 +190,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { ); while (this.connectorsStatus.get(connectorId)?.start === true) { if (!this.canStartConnector(connectorId)) { - await this.stopConnector(connectorId); + this.stopConnector(connectorId); break; } if (!this.chargingStation?.ocppRequestService) { @@ -439,7 +438,7 @@ export class AutomaticTransactionGenerator extends AsyncResource { private async stopTransaction( connectorId: number, - reason: StopTransactionReason = StopTransactionReason.LOCAL, + reason = StopTransactionReason.LOCAL, ): Promise { const measureId = 'StopTransaction with ATG'; const beginId = PerformanceStatistics.beginMeasure(measureId); diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 134ccff6..441c5d1e 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -724,11 +724,11 @@ export class ChargingStation { } } - public async stop(reason?: StopTransactionReason): Promise { + public async stop(reason?: StopTransactionReason, stopTransactions?: boolean): Promise { if (this.started === true) { if (this.stopping === false) { this.stopping = true; - await this.stopMessageSequence(reason); + await this.stopMessageSequence(reason, stopTransactions); this.closeWSConnection(); if (this.getEnableStatistics() === true) { this.performanceStatistics?.stop(); @@ -884,13 +884,13 @@ export class ChargingStation { parentPort?.postMessage(buildUpdatedMessage(this)); } - public async stopAutomaticTransactionGenerator(connectorIds?: number[]): Promise { + public stopAutomaticTransactionGenerator(connectorIds?: number[]): void { if (isNotEmptyArray(connectorIds)) { for (const connectorId of connectorIds!) { - await this.automaticTransactionGenerator?.stopConnector(connectorId); + this.automaticTransactionGenerator?.stopConnector(connectorId); } } else { - await this.automaticTransactionGenerator?.stop(); + this.automaticTransactionGenerator?.stop(); } this.saveAutomaticTransactionGeneratorConfiguration(); parentPort?.postMessage(buildUpdatedMessage(this)); @@ -898,7 +898,7 @@ export class ChargingStation { public async stopTransactionOnConnector( connectorId: number, - reason = StopTransactionReason.NONE, + reason?: StopTransactionReason, ): Promise { const transactionId = this.getConnectorStatus(connectorId)?.transactionId; if ( @@ -928,7 +928,7 @@ export class ChargingStation { { transactionId, meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId!, true), - reason, + ...(isNullOrUndefined(reason) && { reason }), }, ); } @@ -2043,7 +2043,7 @@ export class ChargingStation { return stationTemplate?.useConnectorId0 ?? true; } - private async stopRunningTransactions(reason = StopTransactionReason.NONE): Promise { + private async stopRunningTransactions(reason?: StopTransactionReason): Promise { if (this.hasEvses) { for (const [evseId, evseStatus] of this.evses) { if (evseId === 0) { @@ -2178,17 +2178,18 @@ export class ChargingStation { } private async stopMessageSequence( - reason: StopTransactionReason = StopTransactionReason.NONE, + reason?: StopTransactionReason, + stopTransactions = true, ): Promise { // Stop WebSocket ping this.stopWebSocketPing(); // Stop heartbeat this.stopHeartbeat(); // Stop ongoing transactions + stopTransactions && (await this.stopRunningTransactions(reason)); + // Stop the ATG if (this.automaticTransactionGenerator?.started === true) { - await this.stopAutomaticTransactionGenerator(); - } else { - await this.stopRunningTransactions(reason); + this.stopAutomaticTransactionGenerator(); } if (this.hasEvses) { for (const [evseId, evseStatus] of this.evses) { @@ -2333,7 +2334,7 @@ export class ChargingStation { this.stopHeartbeat(); // Stop the ATG if needed if (this.getAutomaticTransactionGeneratorConfiguration().stopOnConnectionFailure === true) { - await this.stopAutomaticTransactionGenerator(); + this.stopAutomaticTransactionGenerator(); } if ( this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries()! || diff --git a/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts b/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts index ee423e1e..fff823c0 100644 --- a/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts +++ b/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts @@ -87,10 +87,8 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne ], [ BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR, - async (requestPayload?: BroadcastChannelRequestPayload) => - await this.chargingStation.stopAutomaticTransactionGenerator( - requestPayload?.connectorIds, - ), + (requestPayload?: BroadcastChannelRequestPayload) => + this.chargingStation.stopAutomaticTransactionGenerator(requestPayload?.connectorIds), ], [ BroadcastChannelProcedureName.SET_SUPERVISION_URL, diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index d2e19375..03bf1367 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -559,7 +559,7 @@ export class OCPP16ResponseService extends OCPPResponseService { } if (connectorStatus?.transactionStarted === true) { logger.error( - `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${connectorId} by idTag ${connectorStatus?.transactionIdTag}}`, + `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${connectorId} by idTag ${connectorStatus?.transactionIdTag}`, ); return; } @@ -569,7 +569,7 @@ export class OCPP16ResponseService extends OCPPResponseService { for (const [id, status] of evseStatus.connectors) { if (id !== connectorId && status?.transactionStarted === true) { logger.error( - `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId} by connector id ${id} with idTag ${status?.transactionIdTag}}`, + `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId} by connector id ${id} with idTag ${status?.transactionIdTag}`, ); await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); return; diff --git a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts index 17da98c0..04cf899f 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts @@ -123,7 +123,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${socMinimumValue}/${ meterValue.sampledValue[sampledValuesIndex].value - }/${socMaximumValue}}`, + }/${socMaximumValue}`, ); } } diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index 0ccf92fe..fd4d8807 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -104,7 +104,7 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { validate.errors, ); throw new OCPPError( - OCPPServiceUtils.ajvErrorsToErrorType(validate.errors!), + OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), 'Incoming request PDU is invalid', commandName, JSON.stringify(validate.errors, undefined, 2), diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index b95e9d23..bcbbe639 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -230,7 +230,7 @@ export abstract class OCPPRequestService { ); // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). throw new OCPPError( - OCPPServiceUtils.ajvErrorsToErrorType(validate.errors!), + OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), 'Request PDU is invalid', commandName, JSON.stringify(validate.errors, undefined, 2), @@ -285,7 +285,7 @@ export abstract class OCPPRequestService { ); // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). throw new OCPPError( - OCPPServiceUtils.ajvErrorsToErrorType(validate.errors!), + OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), 'Response PDU is invalid', commandName, JSON.stringify(validate.errors, undefined, 2), diff --git a/src/charging-station/ocpp/OCPPResponseService.ts b/src/charging-station/ocpp/OCPPResponseService.ts index b76fde6a..1bc73bc8 100644 --- a/src/charging-station/ocpp/OCPPResponseService.ts +++ b/src/charging-station/ocpp/OCPPResponseService.ts @@ -83,7 +83,7 @@ export abstract class OCPPResponseService { validate.errors, ); throw new OCPPError( - OCPPServiceUtils.ajvErrorsToErrorType(validate.errors!), + OCPPServiceUtils.ajvErrorsToErrorType(validate.errors), 'Response PDU is invalid', commandName, JSON.stringify(validate.errors, undefined, 2), diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index 7c459809..ef16bfb8 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -48,17 +48,19 @@ export class OCPPServiceUtils { // This is intentional } - public static ajvErrorsToErrorType(errors: ErrorObject[]): ErrorType { - for (const error of errors as DefinedError[]) { - switch (error.keyword) { - case 'type': - return ErrorType.TYPE_CONSTRAINT_VIOLATION; - case 'dependencies': - case 'required': - return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION; - case 'pattern': - case 'format': - return ErrorType.PROPERTY_CONSTRAINT_VIOLATION; + public static ajvErrorsToErrorType(errors: ErrorObject[] | null | undefined): ErrorType { + if (isNotEmptyArray(errors) === true) { + for (const error of errors as DefinedError[]) { + switch (error.keyword) { + case 'type': + return ErrorType.TYPE_CONSTRAINT_VIOLATION; + case 'dependencies': + case 'required': + return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION; + case 'pattern': + case 'format': + return ErrorType.PROPERTY_CONSTRAINT_VIOLATION; + } } } return ErrorType.FORMAT_VIOLATION; diff --git a/src/types/ocpp/1.6/Transaction.ts b/src/types/ocpp/1.6/Transaction.ts index 4af42747..586367d7 100644 --- a/src/types/ocpp/1.6/Transaction.ts +++ b/src/types/ocpp/1.6/Transaction.ts @@ -2,7 +2,6 @@ import type { OCPP16MeterValue } from './MeterValues'; import type { JsonObject } from '../../JsonType'; export enum OCPP16StopTransactionReason { - NONE = '', EMERGENCY_STOP = 'EmergencyStop', EV_DISCONNECTED = 'EVDisconnected', HARD_RESET = 'HardReset', -- 2.34.1