From 4ca2e99eddcfbebf0ec9bd7608cbf73ed3581eb5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 28 Mar 2026 17:06:49 +0100 Subject: [PATCH] =?utf8?q?feat:=20implement=20TxEnded=20meter=20value=20ac?= =?utf8?q?cumulator=20per=20OCPP=202.0.1=20spec=20=C2=A72.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Per E06.FR.11 and J02.FR.10, TransactionEvent(Ended) must contain meter values sampled every TxEndedInterval from transaction start, with the final sample marked as Transaction.End context. - Add TxEndedInterval to OCPP20RequiredVariableName enum - Add start/stopEndedMeterValues and getTxEndedInterval - Accumulate periodic samples during transaction, flush in Ended event - Harmonize Updated/Ended naming across API, variables, and log messages - Exclude transactionEndedMeterValues from serialized configuration - Fix stopEndedMeterValues incorrectly called in startUpdatedMeterValues - Restore JSDoc-free ConnectorStatus fields - Fix DEFAULT_WS_PING_INTERVAL constant reference - Update test fixtures and assertions for serialization coverage --- src/charging-station/Helpers.ts | 5 + .../ocpp/1.6/OCPP16IncomingRequestService.ts | 4 +- .../ocpp/1.6/OCPP16ResponseService.ts | 6 +- .../ocpp/1.6/OCPP16ServiceUtils.ts | 62 +++++----- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 2 +- .../ocpp/2.0/OCPP20ResponseService.ts | 4 +- .../ocpp/2.0/OCPP20ServiceUtils.ts | 115 ++++++++++++++---- .../ocpp/2.0/OCPP20VariableRegistry.ts | 62 +++++----- src/charging-station/ocpp/OCPPServiceUtils.ts | 14 +-- src/types/ConnectorStatus.ts | 23 +--- src/types/ocpp/2.0/Variables.ts | 1 + .../ChargingStationConfigurationUtils.ts | 32 ++++- .../ChargingStation-Transactions.test.ts | 34 +++--- .../helpers/StationHelpers.ts | 33 +++-- .../OCPP16Integration-Transactions.test.ts | 4 +- ...OCPP16ResponseService-Transactions.test.ts | 4 +- ...CPP20ServiceUtils-TransactionEvent.test.ts | 18 +-- tests/helpers/TestLifecycleHelpers.ts | 6 +- .../ChargingStationConfigurationUtils.test.ts | 36 ++++-- 19 files changed, 293 insertions(+), 172 deletions(-) diff --git a/src/charging-station/Helpers.ts b/src/charging-station/Helpers.ts index f2c1c9f5..b2bf0cc8 100644 --- a/src/charging-station/Helpers.ts +++ b/src/charging-station/Helpers.ts @@ -565,6 +565,11 @@ export const resetConnectorStatus = (connectorStatus: ConnectorStatus | undefine delete connectorStatus.transactionGroupIdToken connectorStatus.transactionEnergyActiveImportRegisterValue = 0 delete connectorStatus.transactionBeginMeterValue + delete connectorStatus.transactionEndedMeterValues + if (connectorStatus.transactionEndedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionEndedMeterValuesSetInterval) + delete connectorStatus.transactionEndedMeterValuesSetInterval + } delete connectorStatus.transactionSeqNo delete connectorStatus.transactionEvseSent delete connectorStatus.transactionIdTokenSent diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 8266f289..9b4844c6 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -837,8 +837,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { connectorId++ ) { if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) { - OCPP16ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) - OCPP16ServiceUtils.startPeriodicMeterValues( + OCPP16ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) + OCPP16ServiceUtils.startUpdatedMeterValues( chargingStation, connectorId, secondsToMilliseconds(convertToInt(value)) diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 6960de74..c6b383c8 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -453,7 +453,7 @@ export class OCPP16ResponseService extends OCPPResponseService { chargingStation, OCPP16StandardParametersKey.MeterValueSampleInterval ) - OCPP16ServiceUtils.startPeriodicMeterValues( + OCPP16ServiceUtils.startUpdatedMeterValues( chargingStation, connectorId, configuredMeterValueSampleInterval != null @@ -542,7 +542,7 @@ export class OCPP16ResponseService extends OCPPResponseService { ) { transactionConnectorStatus.locked = false } - OCPP16ServiceUtils.stopPeriodicMeterValues(chargingStation, transactionConnectorId) + OCPP16ServiceUtils.stopUpdatedMeterValues(chargingStation, transactionConnectorId) const logMsg = `${chargingStation.logPrefix()} ${moduleName}.handleResponseStopTransaction: Transaction with id ${requestPayload.transactionId.toString()} STOPPED on ${ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions chargingStation.stationInfo?.chargingStationId @@ -562,7 +562,7 @@ export class OCPP16ResponseService extends OCPPResponseService { chargingStation: ChargingStation, connectorId: number ): Promise { - OCPP16ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP16ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) const connectorStatus = chargingStation.getConnectorStatus(connectorId) resetConnectorStatus(connectorStatus) await OCPP16ServiceUtils.restoreConnectorStatus(chargingStation, connectorId, connectorStatus) diff --git a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts index 057a8f40..4b739cd0 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts @@ -589,7 +589,21 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { !cpReplaced && chargingStation.getConnectorStatus(connectorId)?.chargingProfiles?.push(cp) } - public static startPeriodicMeterValues ( + public static async startTransactionOnConnector ( + chargingStation: ChargingStation, + connectorId: number, + idTag?: string + ): Promise { + return chargingStation.ocppRequestService.requestHandler< + Partial, + StartTransactionResponse + >(chargingStation, RequestCommand.START_TRANSACTION, { + connectorId, + ...(idTag != null && { idTag }), + }) + } + + public static startUpdatedMeterValues ( chargingStation: ChargingStation, connectorId: number, interval: number @@ -597,23 +611,23 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { const connectorStatus = chargingStation.getConnectorStatus(connectorId) if (connectorStatus == null) { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: Connector ${connectorId.toString()} not found` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: Connector ${connectorId.toString()} not found` ) return } if (connectorStatus.transactionStarted !== true || connectorStatus.transactionId == null) { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: No active transaction on connector ${connectorId.toString()}` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: No active transaction on connector ${connectorId.toString()}` ) return } if (interval <= 0) { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: MeterValueSampleInterval set to ${interval.toString()}, not sending MeterValues` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: MeterValueSampleInterval set to ${interval.toString()}, not sending MeterValues` ) return } - connectorStatus.transactionMeterValuesSetInterval = setInterval(() => { + connectorStatus.transactionUpdatedMeterValuesSetInterval = setInterval(() => { const transactionId = convertToInt(connectorStatus.transactionId) const meterValue = buildMeterValue(chargingStation, transactionId, interval) chargingStation.ocppRequestService @@ -628,38 +642,13 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { ) .catch((error: unknown) => { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: Error while sending '${RequestCommand.METER_VALUES}':`, + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: Error while sending '${RequestCommand.METER_VALUES}':`, error ) }) }, clampToSafeTimerValue(interval)) } - public static async startTransactionOnConnector ( - chargingStation: ChargingStation, - connectorId: number, - idTag?: string - ): Promise { - return chargingStation.ocppRequestService.requestHandler< - Partial, - StartTransactionResponse - >(chargingStation, RequestCommand.START_TRANSACTION, { - connectorId, - ...(idTag != null && { idTag }), - }) - } - - public static stopPeriodicMeterValues ( - chargingStation: ChargingStation, - connectorId: number - ): void { - const connectorStatus = chargingStation.getConnectorStatus(connectorId) - if (connectorStatus?.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - delete connectorStatus.transactionMeterValuesSetInterval - } - } - public static async stopTransactionOnConnector ( chargingStation: ChargingStation, connectorId: number, @@ -699,6 +688,17 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { }) } + public static stopUpdatedMeterValues ( + chargingStation: ChargingStation, + connectorId: number + ): void { + const connectorStatus = chargingStation.getConnectorStatus(connectorId) + if (connectorStatus?.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + delete connectorStatus.transactionUpdatedMeterValuesSetInterval + } + } + private static readonly composeChargingSchedule = ( chargingSchedule: OCPP16ChargingSchedule, compositeInterval: Interval diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index ea2ad85c..c5376875 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -3045,7 +3045,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { connectorId: number, evseId?: number ): Promise { - OCPP20ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP20ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) const connectorStatus = chargingStation.getConnectorStatus(connectorId) resetConnectorStatus(connectorStatus) await restoreConnectorStatus(chargingStation, connectorId, connectorStatus) diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index a353695d..d76b6288 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -415,11 +415,13 @@ export class OCPP20ResponseService extends OCPPResponseService { ) }) const txUpdatedInterval = OCPP20ServiceUtils.getTxUpdatedInterval(chargingStation) - OCPP20ServiceUtils.startPeriodicMeterValues( + OCPP20ServiceUtils.startUpdatedMeterValues( chargingStation, connectorId, txUpdatedInterval ) + const txEndedInterval = OCPP20ServiceUtils.getTxEndedInterval(chargingStation) + OCPP20ServiceUtils.startEndedMeterValues(chargingStation, connectorId, txEndedInterval) } logger.info( `${chargingStation.logPrefix()} ${moduleName}.handleResponseTransactionEvent: Transaction ${requestPayload.transactionInfo.transactionId} STARTED on connector ${String(connectorId)}` diff --git a/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts b/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts index 90202109..f56c25ef 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts @@ -107,14 +107,14 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { OCPP20ComponentName.SampledDataCtrlr, OCPP20RequiredVariableName.TxStartedMeasurands ) - const meterValue = buildMeterValue( + const startedMeterValue = buildMeterValue( chargingStation, transactionId, 0, measurandsKey, OCPP20ReadingContextEnumType.TRANSACTION_BEGIN ) as OCPP20MeterValue - return meterValue.sampledValue.length > 0 ? [meterValue] : [] + return startedMeterValue.sampledValue.length > 0 ? [startedMeterValue] : [] } catch (error) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.buildTransactionStartedMeterValues: ${(error as Error).message}` @@ -128,7 +128,7 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { connectorId: number, connectorStatus: ConnectorStatus ): Promise { - OCPP20ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP20ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) resetConnectorStatus(connectorStatus) connectorStatus.locked = false await sendAndSetConnectorStatus(chargingStation, { @@ -293,6 +293,15 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { ) } + public static getTxEndedInterval (chargingStation: ChargingStation): number { + return OCPP20ServiceUtils.readVariableAsIntervalMs( + chargingStation, + OCPP20ComponentName.SampledDataCtrlr, + OCPP20RequiredVariableName.TxEndedInterval, + 0 + ) + } + public static getTxUpdatedInterval (chargingStation: ChargingStation): number { return OCPP20ServiceUtils.readVariableAsIntervalMs( chargingStation, @@ -581,7 +590,46 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { } } - public static startPeriodicMeterValues ( + public static startEndedMeterValues ( + chargingStation: ChargingStation, + connectorId: number, + interval: number + ): void { + const connectorStatus = chargingStation.getConnectorStatus(connectorId) + if (connectorStatus == null) { + return + } + connectorStatus.transactionEndedMeterValues = [] + if (interval <= 0) { + return + } + if (connectorStatus.transactionEndedMeterValuesSetInterval != null) { + OCPP20ServiceUtils.stopEndedMeterValues(chargingStation, connectorId) + } + connectorStatus.transactionEndedMeterValuesSetInterval = setInterval(() => { + const cs = chargingStation.getConnectorStatus(connectorId) + if (cs?.transactionStarted === true && cs.transactionId != null) { + const measurandsKey = buildConfigKey( + OCPP20ComponentName.SampledDataCtrlr, + OCPP20RequiredVariableName.TxEndedMeasurands + ) + const meterValue = buildMeterValue( + chargingStation, + cs.transactionId, + interval, + measurandsKey + ) as OCPP20MeterValue + if (meterValue.sampledValue.length > 0) { + cs.transactionEndedMeterValues?.push(meterValue) + } + } + }, clampToSafeTimerValue(interval)) + logger.info( + `${chargingStation.logPrefix()} ${moduleName}.startEndedMeterValues: TxEndedInterval started every ${formatDurationMilliSeconds(interval)}` + ) + } + + public static startUpdatedMeterValues ( chargingStation: ChargingStation, connectorId: number, interval: number @@ -589,23 +637,23 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { const initialConnectorStatus = chargingStation.getConnectorStatus(connectorId) if (initialConnectorStatus == null) { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: Connector ${connectorId.toString()} not found` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: Connector ${connectorId.toString()} not found` ) return } if (interval <= 0) { logger.debug( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: TxUpdatedInterval is ${interval.toString()}, not starting periodic TransactionEvent` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: TxUpdatedInterval is ${interval.toString()}, not starting periodic TransactionEvent` ) return } - if (initialConnectorStatus.transactionMeterValuesSetInterval != null) { + if (initialConnectorStatus.transactionUpdatedMeterValuesSetInterval != null) { logger.warn( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: TxUpdatedInterval already started, stopping first` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: TxUpdatedInterval already started, stopping first` ) - OCPP20ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP20ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) } - initialConnectorStatus.transactionMeterValuesSetInterval = setInterval(() => { + initialConnectorStatus.transactionUpdatedMeterValuesSetInterval = setInterval(() => { const connectorStatus = chargingStation.getConnectorStatus(connectorId) if (connectorStatus?.transactionStarted === true && connectorStatus.transactionId != null) { if ( @@ -632,7 +680,7 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { evseId ).catch((error: unknown) => { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: Error terminating deauthorized transaction:`, + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: Error terminating deauthorized transaction:`, error ) }) @@ -653,14 +701,14 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { { meterValue: [meterValue] } ).catch((error: unknown) => { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: Error sending periodic TransactionEvent:`, + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: Error sending periodic TransactionEvent:`, error ) }) } }, clampToSafeTimerValue(interval)) logger.info( - `${chargingStation.logPrefix()} ${moduleName}.startPeriodicMeterValues: TxUpdatedInterval started every ${formatDurationMilliSeconds(interval)}` + `${chargingStation.logPrefix()} ${moduleName}.startUpdatedMeterValues: TxUpdatedInterval started every ${formatDurationMilliSeconds(interval)}` ) } @@ -723,43 +771,61 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { } } - public static stopPeriodicMeterValues ( + public static stopEndedMeterValues (chargingStation: ChargingStation, connectorId: number): void { + const connectorStatus = chargingStation.getConnectorStatus(connectorId) + if (connectorStatus?.transactionEndedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionEndedMeterValuesSetInterval) + delete connectorStatus.transactionEndedMeterValuesSetInterval + logger.info( + `${chargingStation.logPrefix()} ${moduleName}.stopEndedMeterValues: TxEndedInterval stopped` + ) + } + } + + public static stopUpdatedMeterValues ( chargingStation: ChargingStation, connectorId: number ): void { const connectorStatus = chargingStation.getConnectorStatus(connectorId) - if (connectorStatus?.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - delete connectorStatus.transactionMeterValuesSetInterval + if (connectorStatus?.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + delete connectorStatus.transactionUpdatedMeterValuesSetInterval logger.info( - `${chargingStation.logPrefix()} ${moduleName}.stopPeriodicMeterValues: TxUpdatedInterval stopped` + `${chargingStation.logPrefix()} ${moduleName}.stopUpdatedMeterValues: TxUpdatedInterval stopped` ) } } private static buildTransactionEndedMeterValues ( chargingStation: ChargingStation, + connectorId: number, transactionId: number | string ): OCPP20MeterValue[] { + const connectorStatus = chargingStation.getConnectorStatus(connectorId) + const endedMeterValues = (connectorStatus?.transactionEndedMeterValues ?? + []) as OCPP20MeterValue[] + try { const measurandsKey = buildConfigKey( OCPP20ComponentName.SampledDataCtrlr, OCPP20RequiredVariableName.TxEndedMeasurands ) - const meterValue = buildMeterValue( + const finalMeterValue = buildMeterValue( chargingStation, transactionId, 0, measurandsKey, OCPP20ReadingContextEnumType.TRANSACTION_END ) as OCPP20MeterValue - return meterValue.sampledValue.length > 0 ? [meterValue] : [] + if (finalMeterValue.sampledValue.length > 0) { + return [...endedMeterValues, finalMeterValue] + } } catch (error) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.buildTransactionEndedMeterValues: ${(error as Error).message}` ) - return [] } + return endedMeterValues.length > 0 ? endedMeterValues : [] } private static readVariableAsBoolean ( @@ -863,7 +929,12 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { stoppedReason: OCPP20ReasonEnumType, evseId?: number ): Promise { - const endedMeterValues = this.buildTransactionEndedMeterValues(chargingStation, transactionId) + this.stopEndedMeterValues(chargingStation, connectorId) + const endedMeterValues = this.buildTransactionEndedMeterValues( + chargingStation, + connectorId, + transactionId + ) const response = await this.sendTransactionEvent( chargingStation, diff --git a/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts b/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts index 2d80aee4..6ff837a6 100644 --- a/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts +++ b/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts @@ -149,20 +149,6 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: 'SignReadings', }, - [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr, 'TxEndedInterval')]: { - component: OCPP20ComponentName.AlignedDataCtrlr, - dataType: DataEnumType.integer, - defaultValue: '900', - description: - 'Size (in seconds) of the clock-aligned data interval, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', - min: 1, - mutability: MutabilityEnumType.ReadWrite, - persistence: PersistenceEnumType.Persistent, - required: true, - supportedAttributes: [AttributeEnumType.Actual], - unit: OCPP20UnitEnumType.SECONDS, - variable: 'TxEndedInterval', - }, [buildRegistryKey( OCPP20ComponentName.AlignedDataCtrlr, OCPP20RequiredVariableName.AlignedDataInterval @@ -224,6 +210,23 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: OCPP20RequiredVariableName.Measurands, }, + [buildRegistryKey( + OCPP20ComponentName.AlignedDataCtrlr, + OCPP20RequiredVariableName.TxEndedInterval + )]: { + component: OCPP20ComponentName.AlignedDataCtrlr, + dataType: DataEnumType.integer, + defaultValue: '900', + description: + 'Size (in seconds) of the clock-aligned data interval, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + required: true, + supportedAttributes: [AttributeEnumType.Actual], + unit: OCPP20UnitEnumType.SECONDS, + variable: OCPP20RequiredVariableName.TxEndedInterval, + }, [buildRegistryKey( OCPP20ComponentName.AlignedDataCtrlr, OCPP20RequiredVariableName.TxEndedMeasurands @@ -1689,20 +1692,6 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: 'SignReadings', }, - [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr, 'TxEndedInterval')]: { - component: OCPP20ComponentName.SampledDataCtrlr, - dataType: DataEnumType.integer, - defaultValue: '60', - description: - 'Interval between sampling of metering data, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', - min: 1, - mutability: MutabilityEnumType.ReadWrite, - persistence: PersistenceEnumType.Persistent, - required: true, - supportedAttributes: [AttributeEnumType.Actual], - unit: OCPP20UnitEnumType.SECONDS, - variable: 'TxEndedInterval', - }, [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr, OCPP20MeasurandEnumType.CURRENT_IMPORT)]: { component: OCPP20ComponentName.SampledDataCtrlr, @@ -1768,6 +1757,23 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: OCPP20RequiredVariableName.Enabled, }, + [buildRegistryKey( + OCPP20ComponentName.SampledDataCtrlr, + OCPP20RequiredVariableName.TxEndedInterval + )]: { + component: OCPP20ComponentName.SampledDataCtrlr, + dataType: DataEnumType.integer, + defaultValue: '60', + description: + 'Interval between sampling of metering data, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + required: true, + supportedAttributes: [AttributeEnumType.Actual], + unit: OCPP20UnitEnumType.SECONDS, + variable: OCPP20RequiredVariableName.TxEndedInterval, + }, [buildRegistryKey( OCPP20ComponentName.SampledDataCtrlr, OCPP20RequiredVariableName.TxEndedMeasurands diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index 517159c3..414f5e8f 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -568,7 +568,7 @@ export const stopRunningTransactions = async ( } } -export const startPeriodicMeterValues = async ( +export const startUpdatedMeterValues = async ( chargingStation: ChargingStation, connectorId: number, interval: number @@ -576,37 +576,37 @@ export const startPeriodicMeterValues = async ( switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: { const { OCPP16ServiceUtils } = await import('./1.6/OCPP16ServiceUtils.js') - OCPP16ServiceUtils.startPeriodicMeterValues(chargingStation, connectorId, interval) + OCPP16ServiceUtils.startUpdatedMeterValues(chargingStation, connectorId, interval) break } case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: { const { OCPP20ServiceUtils } = await import('./2.0/OCPP20ServiceUtils.js') - OCPP20ServiceUtils.startPeriodicMeterValues(chargingStation, connectorId, interval) + OCPP20ServiceUtils.startUpdatedMeterValues(chargingStation, connectorId, interval) break } default: logger.error( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `${chargingStation.logPrefix()} OCPPServiceUtils.startPeriodicMeterValues: unsupported OCPP version ${chargingStation.stationInfo?.ocppVersion}` + `${chargingStation.logPrefix()} OCPPServiceUtils.startUpdatedMeterValues: unsupported OCPP version ${chargingStation.stationInfo?.ocppVersion}` ) } } -export const stopPeriodicMeterValues = async ( +export const stopUpdatedMeterValues = async ( chargingStation: ChargingStation, connectorId: number ): Promise => { switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: { const { OCPP16ServiceUtils } = await import('./1.6/OCPP16ServiceUtils.js') - OCPP16ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP16ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) break } case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: { const { OCPP20ServiceUtils } = await import('./2.0/OCPP20ServiceUtils.js') - OCPP20ServiceUtils.stopPeriodicMeterValues(chargingStation, connectorId) + OCPP20ServiceUtils.stopUpdatedMeterValues(chargingStation, connectorId) break } default: diff --git a/src/types/ConnectorStatus.ts b/src/types/ConnectorStatus.ts index c25c2330..56fb4913 100644 --- a/src/types/ConnectorStatus.ts +++ b/src/types/ConnectorStatus.ts @@ -24,38 +24,21 @@ export interface ConnectorStatus { transactionBeginMeterValue?: MeterValue transactionDeauthorized?: boolean transactionDeauthorizedEnergyWh?: number + transactionEndedMeterValues?: MeterValue[] + transactionEndedMeterValuesSetInterval?: NodeJS.Timeout transactionEnergyActiveImportRegisterValue?: number // In Wh - /** - * OCPP 2.0.1 offline-first: Queue of TransactionEvents waiting to be sent - * Events are queued when station is offline (websocket disconnected) - * and replayed in order when reconnected, with seqNo preserved - */ transactionEventQueue?: QueuedTransactionEvent[] - /** - * OCPP 2.0.1 E01.FR.16 compliance: Track if evse has been sent for current transaction. - * The evse field should only be provided in the first TransactionEventRequest - * that occurs after the EV has connected. - */ transactionEvseSent?: boolean transactionGroupIdToken?: string transactionId?: number | string transactionIdTag?: string - /** - * OCPP 2.0.1 E03.FR.01 compliance: Track if idToken has been sent for current transaction. - * The idToken field should be provided once in the first TransactionEventRequest - * that occurs after the transaction has been authorized. - */ transactionIdTokenSent?: boolean - transactionMeterValuesSetInterval?: NodeJS.Timeout - /** - * OCPP 2.0.1 E02 compliance: Transaction pending CSMS acknowledgment. - * Blocks duplicate RequestStartTransaction until response handler sets transactionStarted. - */ transactionPending?: boolean transactionRemoteStarted?: boolean transactionSeqNo?: number transactionStart?: Date transactionStarted?: boolean + transactionUpdatedMeterValuesSetInterval?: NodeJS.Timeout type?: ConnectorEnumType } diff --git a/src/types/ocpp/2.0/Variables.ts b/src/types/ocpp/2.0/Variables.ts index 72414c6b..1a8608ab 100644 --- a/src/types/ocpp/2.0/Variables.ts +++ b/src/types/ocpp/2.0/Variables.ts @@ -68,6 +68,7 @@ export enum OCPP20RequiredVariableName { StopTxOnEVSideDisconnect = 'StopTxOnEVSideDisconnect', StopTxOnInvalidId = 'StopTxOnInvalidId', TimeSource = 'TimeSource', + TxEndedInterval = 'TxEndedInterval', TxEndedMeasurands = 'TxEndedMeasurands', TxStartedMeasurands = 'TxStartedMeasurands', TxStartPoint = 'TxStartPoint', diff --git a/src/utils/ChargingStationConfigurationUtils.ts b/src/utils/ChargingStationConfigurationUtils.ts index db0e6fb4..a21e28a3 100644 --- a/src/utils/ChargingStationConfigurationUtils.ts +++ b/src/utils/ChargingStationConfigurationUtils.ts @@ -34,7 +34,13 @@ export const buildConnectorEntries = (chargingStation: ChargingStation): Connect return [...chargingStation.connectors.entries()].map( ([ connectorId, - { transactionEventQueue, transactionMeterValuesSetInterval, ...connector }, + { + transactionEndedMeterValues, + transactionEndedMeterValuesSetInterval, + transactionEventQueue, + transactionUpdatedMeterValuesSetInterval, + ...connector + }, ]) => ({ connector, connectorId, @@ -48,7 +54,13 @@ export const buildConnectorsStatus = ( return [...chargingStation.connectors.entries()].map( ([ connectorId, - { transactionEventQueue, transactionMeterValuesSetInterval, ...connectorStatus }, + { + transactionEndedMeterValues, + transactionEndedMeterValuesSetInterval, + transactionEventQueue, + transactionUpdatedMeterValuesSetInterval, + ...connectorStatus + }, ]) => [connectorId, connectorStatus] ) } @@ -59,7 +71,13 @@ export const buildEvseEntries = (chargingStation: ChargingStation): EvseEntry[] connectors: [...evseStatus.connectors.entries()].map( ([ connectorId, - { transactionEventQueue, transactionMeterValuesSetInterval, ...connector }, + { + transactionEndedMeterValues, + transactionEndedMeterValuesSetInterval, + transactionEventQueue, + transactionUpdatedMeterValuesSetInterval, + ...connector + }, ]) => ({ connector, connectorId, @@ -76,7 +94,13 @@ export const buildEvsesStatus = ( const connectorsStatus: [number, ConnectorStatus][] = [...evseStatus.connectors.entries()].map( ([ connectorId, - { transactionEventQueue, transactionMeterValuesSetInterval, ...connector }, + { + transactionEndedMeterValues, + transactionEndedMeterValuesSetInterval, + transactionEventQueue, + transactionUpdatedMeterValuesSetInterval, + ...connector + }, ]) => [connectorId, connector] ) const { connectors: _, ...evseStatusRest } = evseStatus diff --git a/tests/charging-station/ChargingStation-Transactions.test.ts b/tests/charging-station/ChargingStation-Transactions.test.ts index 51baa8c9..826d8e4f 100644 --- a/tests/charging-station/ChargingStation-Transactions.test.ts +++ b/tests/charging-station/ChargingStation-Transactions.test.ts @@ -538,12 +538,12 @@ await describe('ChargingStation Transaction Management', async () => { } // Act - OCPP16ServiceUtils.startPeriodicMeterValues(station, 1, 10000) + OCPP16ServiceUtils.startUpdatedMeterValues(station, 1, 10000) // Assert - meter values interval should be created if (connector1 != null) { - assert.notStrictEqual(connector1.transactionMeterValuesSetInterval, undefined) - assert.strictEqual(typeof connector1.transactionMeterValuesSetInterval, 'object') + assert.notStrictEqual(connector1.transactionUpdatedMeterValuesSetInterval, undefined) + assert.strictEqual(typeof connector1.transactionUpdatedMeterValuesSetInterval, 'object') } }) }) @@ -558,13 +558,13 @@ await describe('ChargingStation Transaction Management', async () => { connector1.transactionStarted = true connector1.transactionId = 100 } - OCPP16ServiceUtils.startPeriodicMeterValues(station, 1, 10000) - const firstInterval = connector1?.transactionMeterValuesSetInterval + OCPP16ServiceUtils.startUpdatedMeterValues(station, 1, 10000) + const firstInterval = connector1?.transactionUpdatedMeterValuesSetInterval // Act - OCPP16ServiceUtils.stopPeriodicMeterValues(station, 1) - OCPP16ServiceUtils.startPeriodicMeterValues(station, 1, 15000) - const secondInterval = connector1?.transactionMeterValuesSetInterval + OCPP16ServiceUtils.stopUpdatedMeterValues(station, 1) + OCPP16ServiceUtils.startUpdatedMeterValues(station, 1, 15000) + const secondInterval = connector1?.transactionUpdatedMeterValuesSetInterval // Assert - interval should be different assert.notStrictEqual(secondInterval, undefined) @@ -583,13 +583,13 @@ await describe('ChargingStation Transaction Management', async () => { connector1.transactionStarted = true connector1.transactionId = 100 } - OCPP16ServiceUtils.startPeriodicMeterValues(station, 1, 10000) + OCPP16ServiceUtils.startUpdatedMeterValues(station, 1, 10000) // Act - OCPP16ServiceUtils.stopPeriodicMeterValues(station, 1) + OCPP16ServiceUtils.stopUpdatedMeterValues(station, 1) // Assert - interval should be cleared - assert.strictEqual(connector1?.transactionMeterValuesSetInterval, undefined) + assert.strictEqual(connector1?.transactionUpdatedMeterValuesSetInterval, undefined) }) }) @@ -608,12 +608,12 @@ await describe('ChargingStation Transaction Management', async () => { } // Act - OCPP20ServiceUtils.startPeriodicMeterValues(station, 1, 5000) + OCPP20ServiceUtils.startUpdatedMeterValues(station, 1, 5000) // Assert - transaction updated interval should be created if (connector1 != null) { - assert.notStrictEqual(connector1.transactionMeterValuesSetInterval, undefined) - assert.strictEqual(typeof connector1.transactionMeterValuesSetInterval, 'object') + assert.notStrictEqual(connector1.transactionUpdatedMeterValuesSetInterval, undefined) + assert.strictEqual(typeof connector1.transactionUpdatedMeterValuesSetInterval, 'object') } }) }) @@ -631,13 +631,13 @@ await describe('ChargingStation Transaction Management', async () => { connector1.transactionStarted = true connector1.transactionId = 100 } - OCPP20ServiceUtils.startPeriodicMeterValues(station, 1, 5000) + OCPP20ServiceUtils.startUpdatedMeterValues(station, 1, 5000) // Act - OCPP20ServiceUtils.stopPeriodicMeterValues(station, 1) + OCPP20ServiceUtils.stopUpdatedMeterValues(station, 1) // Assert - interval should be cleared - assert.strictEqual(connector1?.transactionMeterValuesSetInterval, undefined) + assert.strictEqual(connector1?.transactionUpdatedMeterValuesSetInterval, undefined) }) }) }) diff --git a/tests/charging-station/helpers/StationHelpers.ts b/tests/charging-station/helpers/StationHelpers.ts index 5150dbfa..d4fb9455 100644 --- a/tests/charging-station/helpers/StationHelpers.ts +++ b/tests/charging-station/helpers/StationHelpers.ts @@ -218,18 +218,26 @@ export function cleanupChargingStation (station: ChargingStation): void { // Clear connector transaction state and timers for (const connectorStatus of station.connectors.values()) { - if (connectorStatus.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - connectorStatus.transactionMeterValuesSetInterval = undefined + if (connectorStatus.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + connectorStatus.transactionUpdatedMeterValuesSetInterval = undefined + } + if (connectorStatus.transactionEndedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionEndedMeterValuesSetInterval) + connectorStatus.transactionEndedMeterValuesSetInterval = undefined } } // Clear EVSE connector transaction state and timers for (const evseStatus of station.evses.values()) { for (const connectorStatus of evseStatus.connectors.values()) { - if (connectorStatus.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - connectorStatus.transactionMeterValuesSetInterval = undefined + if (connectorStatus.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + connectorStatus.transactionUpdatedMeterValuesSetInterval = undefined + } + if (connectorStatus.transactionEndedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionEndedMeterValuesSetInterval) + connectorStatus.transactionEndedMeterValuesSetInterval = undefined } } } @@ -974,9 +982,14 @@ function resetConnectorStatus (status: ConnectorStatus, isConnectorZero: boolean status.energyActiveImportRegisterValue = 0 status.transactionEnergyActiveImportRegisterValue = 0 - // Clear transaction interval - if (status.transactionMeterValuesSetInterval != null) { - clearInterval(status.transactionMeterValuesSetInterval) - status.transactionMeterValuesSetInterval = undefined + if (status.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(status.transactionUpdatedMeterValuesSetInterval) + status.transactionUpdatedMeterValuesSetInterval = undefined + } + + status.transactionEndedMeterValues = undefined + if (status.transactionEndedMeterValuesSetInterval != null) { + clearInterval(status.transactionEndedMeterValuesSetInterval) + status.transactionEndedMeterValuesSetInterval = undefined } } diff --git a/tests/charging-station/ocpp/1.6/OCPP16Integration-Transactions.test.ts b/tests/charging-station/ocpp/1.6/OCPP16Integration-Transactions.test.ts index b6f70485..d100bdd9 100644 --- a/tests/charging-station/ocpp/1.6/OCPP16Integration-Transactions.test.ts +++ b/tests/charging-station/ocpp/1.6/OCPP16Integration-Transactions.test.ts @@ -77,14 +77,14 @@ function createIntegrationContext (): { // Mock meter value start/stop to avoid real timer setup mock.method( OCPP16ServiceUtils, - 'startPeriodicMeterValues', + 'startUpdatedMeterValues', (_station: unknown, _connectorId: number, _interval: number) => { /* noop */ } ) mock.method( OCPP16ServiceUtils, - 'stopPeriodicMeterValues', + 'stopUpdatedMeterValues', (_station: unknown, _connectorId: number) => { /* noop */ } diff --git a/tests/charging-station/ocpp/1.6/OCPP16ResponseService-Transactions.test.ts b/tests/charging-station/ocpp/1.6/OCPP16ResponseService-Transactions.test.ts index 61daa7d5..a59a7f8b 100644 --- a/tests/charging-station/ocpp/1.6/OCPP16ResponseService-Transactions.test.ts +++ b/tests/charging-station/ocpp/1.6/OCPP16ResponseService-Transactions.test.ts @@ -42,10 +42,10 @@ await describe('OCPP16ResponseService — StartTransaction and StopTransaction', setMockRequestHandler(station, async () => Promise.resolve({})) // Mock startMeterValues/stopMeterValues to avoid real timer setup - mock.method(OCPP16ServiceUtils, 'startPeriodicMeterValues', () => { + mock.method(OCPP16ServiceUtils, 'startUpdatedMeterValues', () => { /* noop */ }) - mock.method(OCPP16ServiceUtils, 'stopPeriodicMeterValues', () => { + mock.method(OCPP16ServiceUtils, 'stopUpdatedMeterValues', () => { /* noop */ }) diff --git a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts index 7a3500c5..5ca8924f 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts @@ -23,7 +23,7 @@ import { OCPP20ServiceUtils, } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js' import { OCPP20VariableManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableManager.js' -import { startPeriodicMeterValues } from '../../../../src/charging-station/ocpp/OCPPServiceUtils.js' +import { startUpdatedMeterValues } from '../../../../src/charging-station/ocpp/OCPPServiceUtils.js' import { OCPPError } from '../../../../src/exception/index.js' import { AttributeEnumType, @@ -2000,15 +2000,15 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => { // Clean up any running timers for (let connectorId = 1; connectorId <= 3; connectorId++) { const connectorStatus = mockStation.getConnectorStatus(connectorId) - if (connectorStatus?.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - connectorStatus.transactionMeterValuesSetInterval = undefined + if (connectorStatus?.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + connectorStatus.transactionUpdatedMeterValuesSetInterval = undefined } } standardCleanup() }) - await describe('startPeriodicMeterValues', async () => { + await describe('startUpdatedMeterValues', async () => { await it('should not start OCPP 2.0 timer for OCPP 1.6 stations via unified dispatch', async t => { await withMockTimers(t, ['setInterval'], async () => { const { station: ocpp16Station } = createMockChargingStation({ @@ -2019,10 +2019,10 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => { }, }) - await startPeriodicMeterValues(ocpp16Station, 1, 60000) + await startUpdatedMeterValues(ocpp16Station, 1, 60000) const connectorStatus = ocpp16Station.getConnectorStatus(1) - assert.strictEqual(connectorStatus?.transactionMeterValuesSetInterval, undefined) + assert.strictEqual(connectorStatus?.transactionUpdatedMeterValuesSetInterval, undefined) }) }) @@ -2036,7 +2036,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => { // Zero interval should not start timer // This is verified by the implementation logging debug message - assert.strictEqual(connectorStatus.transactionMeterValuesSetInterval, undefined) + assert.strictEqual(connectorStatus.transactionUpdatedMeterValuesSetInterval, undefined) }) await it('should not start timer when interval is negative', () => { @@ -2046,7 +2046,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => { assert(connectorStatus != null) // Negative interval should not start timer - assert.strictEqual(connectorStatus.transactionMeterValuesSetInterval, undefined) + assert.strictEqual(connectorStatus.transactionUpdatedMeterValuesSetInterval, undefined) }) await it('should handle non-existent connector gracefully', () => { diff --git a/tests/helpers/TestLifecycleHelpers.ts b/tests/helpers/TestLifecycleHelpers.ts index 92362823..370c91d4 100644 --- a/tests/helpers/TestLifecycleHelpers.ts +++ b/tests/helpers/TestLifecycleHelpers.ts @@ -113,9 +113,9 @@ export function clearConnectorTransaction (station: ChargingStation, connectorId connectorStatus.idTagLocalAuthorized = false // Clear any transaction interval - if (connectorStatus.transactionMeterValuesSetInterval != null) { - clearInterval(connectorStatus.transactionMeterValuesSetInterval) - connectorStatus.transactionMeterValuesSetInterval = undefined + if (connectorStatus.transactionUpdatedMeterValuesSetInterval != null) { + clearInterval(connectorStatus.transactionUpdatedMeterValuesSetInterval) + connectorStatus.transactionUpdatedMeterValuesSetInterval = undefined } } diff --git a/tests/utils/ChargingStationConfigurationUtils.test.ts b/tests/utils/ChargingStationConfigurationUtils.test.ts index 7ba16216..a7625eca 100644 --- a/tests/utils/ChargingStationConfigurationUtils.test.ts +++ b/tests/utils/ChargingStationConfigurationUtils.test.ts @@ -70,8 +70,10 @@ await describe('ChargingStationConfigurationUtils', async () => { availability: AvailabilityType.Operative, bootStatus: 'Available', MeterValues: [], + transactionEndedMeterValues: [{ sampledValue: [], timestamp: new Date() }], + transactionEndedMeterValuesSetInterval: interval2 as unknown as NodeJS.Timeout, transactionEventQueue: [], - transactionMeterValuesSetInterval: interval1 as unknown as NodeJS.Timeout, + transactionUpdatedMeterValuesSetInterval: interval1 as unknown as NodeJS.Timeout, } as unknown as ConnectorStatus) const station = createMockStationForConfigUtils({ connectors }) @@ -79,7 +81,9 @@ await describe('ChargingStationConfigurationUtils', async () => { assert.strictEqual(result.length, 2) for (const [, connector] of result) { - assert.ok(!('transactionMeterValuesSetInterval' in connector)) + assert.ok(!('transactionEndedMeterValues' in connector)) + assert.ok(!('transactionEndedMeterValuesSetInterval' in connector)) + assert.ok(!('transactionUpdatedMeterValuesSetInterval' in connector)) assert.ok(!('transactionEventQueue' in connector)) } assert.strictEqual(result[0][0], 0) @@ -105,8 +109,8 @@ await describe('ChargingStationConfigurationUtils', async () => { MeterValues: [], transactionEventQueue: undefined, transactionId: 42, - transactionMeterValuesSetInterval: undefined, transactionStarted: true, + transactionUpdatedMeterValuesSetInterval: undefined, } as unknown as ConnectorStatus) const station = createMockStationForConfigUtils({ connectors }) @@ -147,7 +151,7 @@ await describe('ChargingStationConfigurationUtils', async () => { availability: AvailabilityType.Operative, MeterValues: [], transactionEventQueue: [], - transactionMeterValuesSetInterval: undefined, + transactionUpdatedMeterValuesSetInterval: undefined, } as unknown as ConnectorStatus) const evses = new Map() @@ -178,8 +182,10 @@ await describe('ChargingStationConfigurationUtils', async () => { evseConnectors.set(1, { availability: AvailabilityType.Operative, MeterValues: [], + transactionEndedMeterValues: [{ sampledValue: [], timestamp: new Date() }], + transactionEndedMeterValuesSetInterval: undefined, transactionEventQueue: [], - transactionMeterValuesSetInterval: undefined, + transactionUpdatedMeterValuesSetInterval: undefined, } as unknown as ConnectorStatus) const evses = new Map() @@ -201,7 +207,9 @@ await describe('ChargingStationConfigurationUtils', async () => { assert.strictEqual(connectorsStatus.length, 1) assert.strictEqual(connectorsStatus[0][0], 1) const connectorStatus = connectorsStatus[0][1] - assert.ok(!('transactionMeterValuesSetInterval' in connectorStatus)) + assert.ok(!('transactionEndedMeterValues' in connectorStatus)) + assert.ok(!('transactionEndedMeterValuesSetInterval' in connectorStatus)) + assert.ok(!('transactionUpdatedMeterValuesSetInterval' in connectorStatus)) assert.ok(!('transactionEventQueue' in connectorStatus)) }) @@ -390,8 +398,10 @@ await describe('ChargingStationConfigurationUtils', async () => { connectors.set(1, { availability: AvailabilityType.Operative, MeterValues: [], + transactionEndedMeterValues: [{ sampledValue: [], timestamp: new Date() }], + transactionEndedMeterValuesSetInterval: undefined, transactionEventQueue: [], - transactionMeterValuesSetInterval: undefined, + transactionUpdatedMeterValuesSetInterval: undefined, } as unknown as ConnectorStatus) const station = createMockStationForConfigUtils({ connectors }) @@ -401,7 +411,9 @@ await describe('ChargingStationConfigurationUtils', async () => { assert.strictEqual(result[0].connectorId, 0) assert.strictEqual(result[1].connectorId, 1) assert.strictEqual(result[1].connector.availability, AvailabilityType.Operative) - assert.ok(!('transactionMeterValuesSetInterval' in result[1].connector)) + assert.ok(!('transactionEndedMeterValues' in result[1].connector)) + assert.ok(!('transactionEndedMeterValuesSetInterval' in result[1].connector)) + assert.ok(!('transactionUpdatedMeterValuesSetInterval' in result[1].connector)) assert.ok(!('transactionEventQueue' in result[1].connector)) }) @@ -443,8 +455,10 @@ await describe('ChargingStationConfigurationUtils', async () => { evseConnectors.set(1, { availability: AvailabilityType.Operative, MeterValues: [], + transactionEndedMeterValues: [{ sampledValue: [], timestamp: new Date() }], + transactionEndedMeterValuesSetInterval: undefined, transactionEventQueue: [], - transactionMeterValuesSetInterval: undefined, + transactionUpdatedMeterValuesSetInterval: undefined, } as unknown as ConnectorStatus) const evses = new Map() @@ -467,7 +481,9 @@ await describe('ChargingStationConfigurationUtils', async () => { assert.strictEqual(result[1].evseId, 1) assert.strictEqual(result[1].connectors.length, 1) assert.strictEqual(result[1].connectors[0].connectorId, 1) - assert.ok(!('transactionMeterValuesSetInterval' in result[1].connectors[0].connector)) + assert.ok(!('transactionEndedMeterValues' in result[1].connectors[0].connector)) + assert.ok(!('transactionEndedMeterValuesSetInterval' in result[1].connectors[0].connector)) + assert.ok(!('transactionUpdatedMeterValuesSetInterval' in result[1].connectors[0].connector)) assert.ok(!('transactionEventQueue' in result[1].connectors[0].connector)) }) -- 2.43.0