From: Jérôme Benoit Date: Sat, 28 Mar 2026 16:06:49 +0000 (+0100) Subject: feat: implement TxEnded meter value accumulator per OCPP 2.0.1 spec §2.1 X-Git-Tag: ocpp-server@v4.0.0~7 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=4ca2e99eddcfbebf0ec9bd7608cbf73ed3581eb5;p=e-mobility-charging-stations-simulator.git feat: implement TxEnded meter value accumulator per OCPP 2.0.1 spec §2.1 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 --- 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)) })