Meter Values Flows - CSMS Developer Guide
Based on OCPP 2.0.1 Edition 4 Specification (Part 2, Section J). This guide covers all meter value flows from the CSMS (Charging Station Management System) perspective.
1 Overview
This Functional Block describes the functionality that enables a Charging Station to send periodic, possibly clock-aligned MeterValues to the CSMS.
Meter value data can be recorded and transmitted in different ways depending on its intended purpose. The two primary use cases are:
Frequent (e.g. 1-5 minute interval) readings transmitted during a transaction via TransactionEventRequest (eventType = Updated). These are never sent via MeterValuesRequest.
Readings taken at specific clock-aligned times (e.g. every quarter hour) from fiscally
certified energy meters. Sent via standalone MeterValuesRequest messages (or via TransactionEventRequest if during a transaction).
Key Distinction
| Meter Value Type | During Transaction | Outside Transaction | Message Used |
|---|---|---|---|
| Transaction Meter Values | Yes (only) | No | TransactionEventRequest (eventType=Updated) |
| Clock-Aligned Meter Values | Via TransactionEventRequest with triggerReason= MeterValueClock | Via MeterValuesRequest | Either |
MeterValuesRequest. They are
always sent via TransactionEventRequest.2 Configuration Variables
The CSMS can configure meter value behavior on the Charging Station using SetVariablesRequest. These are the
relevant configuration variables:
Transaction Meter Values
| Variable | Description |
|---|---|
| SampledDataCtrlr.TxStartedMeasurands | Comma-separated list of measurands to include in TransactionEventRequest (eventType = Started) meterValues
field |
| SampledDataCtrlr.TxUpdatedMeasurands | Comma-separated list of measurands to include in TransactionEventRequest (eventType = Updated) meterValues
field, every TxUpdatedInterval seconds |
| SampledDataCtrlr.TxUpdatedInterval | Time in seconds between sampling of metering data during a transaction (eventType = Updated). Value of "0" means
no sampled data should be transmitted |
| SampledDataCtrlr.TxEndedMeasurands | Comma-separated list of measurands to include in TransactionEventRequest (eventType = Ended). Measurands
must be taken every TxEndedInterval seconds from the start of the transaction |
| SampledDataCtrlr.TxEndedInterval | Time in seconds between sampling of metering data for the TransactionEventRequest (eventType = Ended) message |
TxEndedMeasurands to a minimum and configure a large interval in TxEndedInterval to keep the amount of data expected at end-of-transaction manageable.Clock-Aligned Meter Values
| Variable | Description |
|---|---|
| AlignedDataCtrlr.Measurands | Comma-separated list of measurands to include in MeterValuesRequest PDU, every AlignedDataCtrlr.Interval seconds |
| AlignedDataCtrlr.Interval | Size of clock-aligned data interval in seconds. Evenly spaced intervals per day starting at 00:00:00 midnight. Value of "0" means no clock-aligned data. E.g. 900 = every 15 minutes |
| AlignedDataCtrlr.TxEndedMeasurands | Comma-separated list of clock-aligned periodic measurands for TransactionEventRequest (eventType = Ended) PDU, every TxEndedInterval |
| AlignedDataCtrlr.TxEndedInterval | Size of clock-aligned data interval for TransactionEventRequest (eventType = Ended) |
| AlignedDataCtrlr.SendDuringIdle | When true, only send clock-aligned meter values when there are no ongoing transactions |
Additional Configuration Variables
| Variable | Description |
|---|---|
| AlignedDataCtrlr.UpstreamMeasurands | Measurands for upstream (grid connection) meter |
| AlignedDataCtrlr.UpstreamInterval | Interval for upstream meter readings |
| AlignedDataSignReadings | When true, Charging Station retrieves signed meter values and puts them in signedMeterValue field |
| SampledDataSignReadings | When true, Charging Station retrieves signed meter values for sampled data |
| SampledDataRegisterValuesWithoutPhases | When true, only report total energy over all phases (no individual phase values) for Energy.Active.Import.Register |
Configuration Examples
TxStartedMeasurands and TxUpdatedMeasurands = emptyTxEndedMeasurands = "Energy.Active.Import.Register"TxEndedInterval = 0TxStartedMeasurands = "Energy.Active.Import.Register"TxUpdatedMeasurands = "Energy.Active.Import.Register"TxUpdatedInterval = 300 (every
5 minutes)TxEndedMeasurands = "Energy.Active.Import.Register"TxEndedInterval = 0TxStartedMeasurands and TxUpdatedMeasurands = emptyTxEndedMeasurands = "Energy.Active.Import.Register"TxEndedInterval = 0AlignedDataCtrlr.Measurands =
"Energy.Active.Import.Register"AlignedDataCtrlr.Interval = 300
(every 5 minutes)3 Data Types & JSON Schemas
MeterValuesRequest CS → CSMS
OCPP Action: MeterValues
Direction: Charging Station → CSMS (CALL)
{
"evseId": 1,
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 1500.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Clock",
"location": "Outlet",
"unitOfMeasure": {
"unit": "Wh",
"multiplier": 0
}
}
]
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
| evseId | integer | Yes | EVSE identifier (>0). Use 0 to designate the main power meter |
| meterValue | MeterValueType[] | Yes | Array of meter value sets (min 1 item) |
MeterValuesResponse CSMS → CS
OCPP Action: MeterValues
Direction: CSMS → Charging Station (CALLRESULT)
The response body is empty (no required fields). The CSMS simply acknowledges receipt:
{}MeterValueType
| Field | Type | Required | Description |
|---|---|---|---|
| timestamp | dateTime (string) | Yes | Timestamp for when the sampled value(s) were taken. Applies to all SampledValues within |
| sampledValue | SampledValueType[] | Yes | Array of sampled values (min 1 item). All values sampled at the same point in time |
SampledValueType
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| value | number | Yes | - | The measured value |
| context | ReadingContextEnumType | No | Sample.Periodic | Reason/event triggering the reading |
| measurand | MeasurandEnumType | No | Energy.Active.Import.Register | Type of measurement |
| phase | PhaseEnumType | No | - | Phase(s) the value applies to. When absent, interpreted as overall value |
| location | LocationEnumType | No | Outlet | Where the measurement was sampled |
| signedMeterValue | SignedMeterValueType | No | - | Digitally signed meter value data |
| unitOfMeasure | UnitOfMeasureType | No | Wh (for energy) | Unit and multiplier |
Enumerations
ReadingContextEnumType
| Value | Description |
|---|---|
| Interruption.Begin | Value at the start of an interruption |
| Interruption.End | Value at the end of an interruption |
| Other | Other context |
| Sample.Clock | Clock-aligned periodic sample |
| Sample.Periodic | Transaction-related periodic sample (default) |
| Transaction.Begin | Value at the beginning of a transaction |
| Transaction.End | Value at the end of a transaction |
| Trigger | Value taken in response to a TriggerMessage |
MeasurandEnumType (Selected Values)
| Value | Unit | Description |
|---|---|---|
| Current.Export | A | Instantaneous current flowing from EV |
| Current.Import | A | Instantaneous current flowing to EV |
| Current.Offered | A | Maximum current offered to EV |
| Energy.Active.Import.Register | Wh | Energy imported (register, monotonic) (default) |
| Energy.Active.Export.Register | Wh | Energy exported (register, monotonic) |
| Power.Active.Import | W | Active power imported |
| SoC | Percent | State of Charge of the EV battery |
| Voltage | V | AC RMS supply voltage |
Note: This is a subset of available measurands. See OCPP 2.0.1 specification for the complete list.
PhaseEnumType
| Value | Description |
|---|---|
| L1 | Phase L1 measured against neutral |
| L2 | Phase L2 measured against neutral |
| L3 | Phase L3 measured against neutral |
| L1-N | Phase L1 to neutral |
| L2-N | Phase L2 to neutral |
| L3-N | Phase L3 to neutral |
| L1-L2 | Phase L1 to L2 |
| L2-L3 | Phase L2 to L3 |
| L3-L1 | Phase L3 to L1 |
LocationEnumType
| Value | Description |
|---|---|
| Body | Body of the Charging Station |
| Cable | Charging cable |
| EV | Electric Vehicle |
| Inlet | Grid inlet (upstream) |
| Outlet | Connector outlet (default) |
TransactionEventRequest — meterValue field CS → CSMS
Transaction-related meter values are sent as part of the TransactionEventRequest message in the optional meterValue field. The structure is identical to MeterValuesRequest.meterValue.
| Field | Type | Required | Description |
|---|---|---|---|
| eventType | TransactionEventEnumType | Yes | Started, Updated, or Ended |
| timestamp | dateTime | Yes | When the event occurred |
| triggerReason | TriggerReasonEnumType | Yes | Why this event was sent (e.g. MeterValuePeriodic, MeterValueClock) |
| meterValue | MeterValueType[] | No | Array of meter values (same structure as MeterValuesRequest) |
4 OCPP Messages
MeterValues Message CS ↔ CSMS
Used for sending clock-aligned meter values when no transaction is running, or for sending main power meter (evseId=0) values.
[2, "msg001", "MeterValues", {
"evseId": 1,
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 15234.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Clock",
"location": "Outlet",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
},
{
"value": 230.1,
"measurand": "Voltage",
"context": "Sample.Clock",
"phase": "L1-N",
"location": "Outlet",
"unitOfMeasure": { "unit": "V", "multiplier": 0 }
}
]
}
]
}][2, "msg002", "MeterValues", {
"evseId": 0,
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 85432.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Clock",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
}
]
}
]
}]The CSMS always responds with an empty body to acknowledge receipt. Failing to respond will cause the CS to retry the same message.
[3, "msg001", {}]TransactionEvent Message CS ↔ CSMS
Transaction-related meter values are always sent via TransactionEventRequest (never via MeterValuesRequest).
[2, "msg042", "TransactionEvent", {
"eventType": "Updated",
"timestamp": "2024-01-15T10:35:00Z",
"triggerReason": "MeterValuePeriodic",
"seqNo": 5,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "Charging",
"timeSpentCharging": 300
},
"meterValue": [
{
"timestamp": "2024-01-15T10:35:00Z",
"sampledValue": [
{
"value": 2500.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Periodic",
"location": "Outlet",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
},
{
"value": 7200.0,
"measurand": "Power.Active.Import",
"context": "Sample.Periodic",
"location": "Outlet",
"unitOfMeasure": { "unit": "W", "multiplier": 0 }
},
{
"value": 72,
"measurand": "SoC",
"context": "Sample.Periodic",
"location": "EV",
"unitOfMeasure": { "unit": "Percent", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 }
}][2, "msg040", "TransactionEvent", {
"eventType": "Started",
"timestamp": "2024-01-15T10:30:00Z",
"triggerReason": "Authorized",
"seqNo": 0,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "EVConnected"
},
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 10000.0,
"measurand": "Energy.Active.Import.Register",
"context": "Transaction.Begin",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 },
"idToken": { "idToken": "AABBCCDD", "type": "ISO14443" }
}][2, "msg050", "TransactionEvent", {
"eventType": "Ended",
"timestamp": "2024-01-15T11:30:00Z",
"triggerReason": "StopAuthorized",
"seqNo": 18,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "Idle",
"stoppedReason": "Local",
"timeSpentCharging": 3420
},
"meterValue": [
{
"timestamp": "2024-01-15T11:30:00Z",
"sampledValue": [
{
"value": 17500.0,
"measurand": "Energy.Active.Import.Register",
"context": "Transaction.End",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 },
"idToken": { "idToken": "AABBCCDD", "type": "ISO14443" }
}]The CSMS can optionally include running cost or final cost in the response.
[3, "msg042", {
"totalCost": 1.25
}][3, "msg042", {}][3, "msg050", {
"totalCost": 3.75,
"idTokenInfo": { "status": "Accepted" }
}]J01 Sending Meter Values Not Related to a Transaction
Scenario Description
- The Charging Station sends a
MeterValuesRequestmessage, for offloading Meter Values to the CSMS. - Upon receipt of a
MeterValuesRequestmessage, the CSMS responds with aMeterValuesResponsemessage.
Sequence Diagram
┌─────────────────┐ ┌──────┐
│ Charging Station│ │ CSMS │
└────────┬────────┘ └──┬───┘
│ │
│ MeterValuesRequest(evseId, meterValue) │
│─────────────────────────────────────────>│
│ │
│ MeterValuesResponse() │
│<─────────────────────────────────────────│
│ │CSMS Handling
When the CSMS receives a MeterValuesRequest:
- Parse the request: Extract
evseIdandmeterValuearray - Identify the EVSE:
evseId > 0refers to a specific EVSE;evseId = 0refers to the main power meter of the Charging Station - Store the meter values: For each
MeterValueTypein the array:- Record the timestamp
- For each
SampledValueTypein sampledValue:- Store value with the associated measurand (default:
Energy.Active.Import.Register) - Record context (default:
Sample.Periodic), location (default:Outlet), phase, and unitOfMeasure - If
signedMeterValueis present, store the signed data for audit/verification purposes
- Store value with the associated measurand (default:
- Respond with MeterValuesResponse: The response body is empty (
{}). Always respond to avoid the Charging Station retrying.
Example Request/Response
[2, "msg001", "MeterValues", {
"evseId": 1,
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 15234.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Clock",
"location": "Outlet",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
},
{
"value": 230.1,
"measurand": "Voltage",
"context": "Sample.Clock",
"phase": "L1-N",
"location": "Outlet",
"unitOfMeasure": { "unit": "V", "multiplier": 0 }
},
{
"value": 16.5,
"measurand": "Current.Import",
"context": "Sample.Clock",
"phase": "L1",
"location": "Outlet",
"unitOfMeasure": { "unit": "A", "multiplier": 0 }
}
]
}
]
}][3, "msg001", {}]Key Requirements (CSMS)
- The CSMS SHALL respond with MeterValuesResponse. Failing to respond might cause the CS to retry the same message
- When
evseId = 0, the message is associated with the entire Charging Station (main power meter) - When a Charging Station has measurands configured that can be measured on multiple locations or phases, then all possible locations and/or phases SHALL be reported
Multiple Locations/Phases
When a Charging Station has measurands configured that can be measured on multiple locations or phases, then all possible locations and/or phases SHALL be reported.
A CS capable of measuring Current.Import on:
- Inlet (3 phases)
- Outlet (3 phases per EVSE on both EVSEs)
With AlignedDataCtrlr.Interval = 900 (every 15 minutes), the CS sends:
- MeterValuesRequest with evseId=0: 3 SampledValue elements (one per phase, location=Inlet)
- MeterValuesRequest with evseId=1: 3 SampledValue elements (one per phase, location=Outlet)
- MeterValuesRequest with evseId=2: 3 SampledValue elements (one per phase, location=Outlet)
J02 Sending Transaction Related Meter Values
Scenario Description
- The Charging Station sends a
TransactionEventRequest(eventType =Updated) message, for offloading Meter Values to the CSMS. - Upon receipt of the
TransactionEventRequestmessage, the CSMS responds with aTransactionEventResponsemessage.
Sequence Diagram
┌─────────────────┐ ┌──────┐
│ Charging Station│ │ CSMS │
└────────┬────────┘ └──┬───┘
│ │
│ TransactionEventRequest(eventType=Updated, transactionId, meterValues) │
│─────────────────────────────────────────────────────────────────────────>│
│ │
│ TransactionEventResponse() │
│<─────────────────────────────────────────────────────────────────────────│
│ │CSMS Handling
When the CSMS receives a TransactionEventRequest with eventType = Updated containing meterValue:
- Identify the transaction: Use
transactionInfo.transactionIdto locate the ongoing transaction - Validate the sequence: Check
seqNoto ensure message ordering and detect gaps - Check if offline: If
offline = true, the data was queued while the CS was offline - Process meter values: For each
MeterValueTypein themeterValuearray:- Record the timestamp
- For each SampledValueType: Store value, measurand, context, location, phase, unitOfMeasure
- Store signedMeterValue if present
- Validate register values: All "Register" type values (e.g.
Energy.Active.Import.Register) MUST be monotonically increasing in time (except meter replacement cases) - Respond with TransactionEventResponse: Always respond. Can optionally include
totalCost,chargingPriority,idTokenInfo, orupdatedPersonalMessage
Example Request/Response
Periodic meter value during transaction (eventType=Updated)
[2, "msg042", "TransactionEvent", {
"eventType": "Updated",
"timestamp": "2024-01-15T10:35:00Z",
"triggerReason": "MeterValuePeriodic",
"seqNo": 5,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "Charging",
"timeSpentCharging": 300
},
"meterValue": [
{
"timestamp": "2024-01-15T10:35:00Z",
"sampledValue": [
{
"value": 2500.0,
"measurand": "Energy.Active.Import.Register",
"context": "Sample.Periodic",
"location": "Outlet",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
},
{
"value": 7200.0,
"measurand": "Power.Active.Import",
"context": "Sample.Periodic",
"location": "Outlet",
"unitOfMeasure": { "unit": "W", "multiplier": 0 }
},
{
"value": 72,
"measurand": "SoC",
"context": "Sample.Periodic",
"location": "EV",
"unitOfMeasure": { "unit": "Percent", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 }
}][3, "msg042", {
"totalCost": 1.25
}]Transaction start with meter values (eventType=Started)
[2, "msg040", "TransactionEvent", {
"eventType": "Started",
"timestamp": "2024-01-15T10:30:00Z",
"triggerReason": "Authorized",
"seqNo": 0,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "EVConnected"
},
"meterValue": [
{
"timestamp": "2024-01-15T10:30:00Z",
"sampledValue": [
{
"value": 10000.0,
"measurand": "Energy.Active.Import.Register",
"context": "Transaction.Begin",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 },
"idToken": { "idToken": "AABBCCDD", "type": "ISO14443" }
}]Transaction end with meter values (eventType=Ended)
[2, "msg050", "TransactionEvent", {
"eventType": "Ended",
"timestamp": "2024-01-15T11:30:00Z",
"triggerReason": "StopAuthorized",
"seqNo": 18,
"transactionInfo": {
"transactionId": "txn-abc-123",
"chargingState": "Idle",
"stoppedReason": "Local",
"timeSpentCharging": 3420
},
"meterValue": [
{
"timestamp": "2024-01-15T11:30:00Z",
"sampledValue": [
{
"value": 17500.0,
"measurand": "Energy.Active.Import.Register",
"context": "Transaction.End",
"unitOfMeasure": { "unit": "Wh", "multiplier": 0 }
}
]
}
],
"evse": { "id": 1, "connectorId": 1 },
"idToken": { "idToken": "AABBCCDD", "type": "ISO14443" }
}][3, "msg050", {
"totalCost": 3.75,
"idTokenInfo": { "status": "Accepted" }
}]Key Requirements (CSMS)
- The CSMS SHALL respond with TransactionEventResponse. Failing to respond might cause the CS to retry
- All "Register" values MUST be monotonically increasing in time (except for meter replacement)
- "*.Register" values SHOULD be read directly from non-volatile register in metering hardware, and SHOULD NOT be re-based to zero at start of transactions
- Meter values in a TransactionEventRequest SHALL all be related to the EVSE on which the transaction is taking place
Offline Behavior
When the Charging Station is offline during a transaction:
- The CS MUST queue all transaction-related messages (including meter values)
- When running low on memory, the CS MAY drop
TransactionEventRequest(eventType=Updated) messages - When dropping messages, the CS SHALL drop intermediate messages first (2nd, 4th, 6th message, etc.) rather than dropping from the start or end
- When removing samples from the eventType=Ended message due to size, intermediate samples should be removed in a way that does not affect billing
J03 Charging Loop with Metering Information Exchange (ISO 15118)
Scenario Description
This use case combines ISO 15118 communication between the EV and Charging Station with OCPP communication between the Charging Station and CSMS:
ISO 15118 phase:
- 1a (AC Charging): The EV sends a
ChargingStatusReqmessage to the Charging Station, which returns aChargingStatusRescontaining the meter value from the fiscal meter.
1b (DC Charging): The EV sends aCurrentDemandReqmessage to the Charging Station, which returns aCurrentDemandRescontaining the meter value from the fiscal meter. - The EV sends a
MeteringReceiptReqto the Charging Station to acknowledge receipt of the meter value.
OCPP phase:
- The Charging Station sends a
TransactionEventRequest(eventType =Updated, with signed meter values) to the CSMS. - The CSMS responds with a
TransactionEventResponse.
Sequence Diagram
┌────┐ ┌─────────────────┐ ┌──────┐
│ EV │ │ Charging Station│ │ CSMS │
└─┬──┘ └────────┬────────┘ └──┬───┘
│ │ │
│ [if AC Charging] │ │
│ ChargingStatusReq() │ │
│────────────────────>│ │
│ │ │
│ ChargingStatusRes(MeterInfoRecord{MeterId, │
│ MeterReading, MeterStatus, │
│ SignedMeterReading, timeStamp}, │
│ ReceiptRequired: True) │
│<────────────────────│ │
│ │ │
│ MeteringReceiptReq( │ │
│ Signature to │ │
│ confirm data) │ │
│────────────────────>│ │
│ │ │
│ MeteringReceiptRes()│ │
│<────────────────────│ │
│ │ │
│ │ TransactionEventRequest(eventType=Updated, │
│ │ transactionID, timestamp, │
│ │ chargingState=Charging, Signed metervalues) │
│ │───────────────────────────────────────────────────────────────────────> │
│ │ │
│ │ TransactionEventResponse() │
│ │<───────────────────────────────────────────────────────────────────────│
│ │ │CSMS Handling
When the CSMS receives a TransactionEventRequest with signed meter values from an ISO 15118 charging session:
- Process the transaction event the same as J02 — store the meter values including
signedMeterValuedata - Store signed meter data: The
signedMeterValuefield inSampledValueTypecontains:signedMeterData: Base64 encoded signed data from the fiscal metersigningMethod: The digital signature method usedencodingMethod: How meter values were encoded before signingpublicKey: Base64 encoded public key for signature verification
- Respond with TransactionEventResponse: Same as J02
SignedMeterValueType
| Field | Type | Required | Description |
|---|---|---|---|
| signedMeterData | string (max 2500) | Yes | Base64 encoded signed data (may contain timestamps, customer references, etc.) |
| signingMethod | string (max 50) | Yes | Method used to create the digital signature |
| encodingMethod | string (max 50) | Yes | Method used to encode meter values before signing |
| publicKey | string (max 2500) | Yes | Base64 encoded public key (sending depends on PublicKeyWithSignedMeterValue config) |
Key Takeaway for CSMS
J03 does not change CSMS handling compared to J02. The CSMS receives TransactionEventRequest messages with meter values (potentially signed) and responds with TransactionEventResponse.
The ISO 15118 metering receipt exchange (MeteringReceiptReq/MeteringReceiptRes)
happens between the EV and CS only, and is transparent to the CSMS.
CSMS Implementation Checklist
- Register handler for MeterValues action
- Parse evseId and meterValue array from request
- Handle evseId = 0 as the main power meter (Charging Station level)
- Handle evseId > 0 as specific EVSE meter values
- Store each MeterValueType with its timestamp and all SampledValue entries
- Apply defaults when optional fields are absent (measurand=Energy.Active.Import.Register, context=Sample.Periodic, location=Outlet, unit=Wh, multiplier=0)
- Store signedMeterValue when present
- Always respond with empty MeterValuesResponse ({})
- In the TransactionEvent handler, check for the optional meterValue field
- Associate meter values with the transaction (via transactionInfo.transactionId)
- Handle all three eventTypes (Started, Updated, Ended) with their respective meter value contexts
- Validate seqNo for message ordering and gap detection
- Handle offline = true events (queued data from offline period)
- Validate that "Register" measurands are monotonically increasing
- Store signed meter values when present
- Respond with TransactionEventResponse — optionally including totalCost for running cost or final cost at end
- Handle multiple messages with same timestamp (large meter data split across messages)
- No special handling needed beyond J02
- Store signedMeterValue data for audit/verification
- Be prepared to receive signed meter values in TransactionEventRequest messages