OCPP MeterValues: What Gets Reported and How Often

MeterValues carries the energy data that drives billing and analytics. What it contains, how often it should fire, and where it goes wrong in production.

MeterValues is the OCPP message that carries the data your billing system, dashboards, and analytics all depend on. Every session generates a stream of MeterValues messages reporting energy delivered, current power, voltage, current, temperature, state of charge, and whatever else the charger is capable of sampling.

It’s also one of the messages where implementations vary the most. Two chargers from different OEMs, charging the same vehicle at the same rate, can report dramatically different MeterValues: different measurands, different frequencies, different precision. Understanding what is being reported, and how to absorb the variation, is essential for any team building a CSMS or working with charging data.

This article covers MeterValues in depth: structure, configuration, the common measurands, and the operational issues that cause real support tickets. If you are new to the protocol, start with what OCPP is and how it works. For where these readings sit in a session, see the full message flow, and for the pair of readings that actually drive the bill, StartTransaction and StopTransaction.

The structure

A MeterValues message in OCPP 1.6:

{
  "connectorId": 1,
  "transactionId": 12345,
  "meterValue": [
    {
      "timestamp": "2026-06-26T19:15:00Z",
      "sampledValue": [
        {
          "value": "12.45",
          "context": "Sample.Periodic",
          "format": "Raw",
          "measurand": "Energy.Active.Import.Register",
          "unit": "kWh"
        },
        {
          "value": "11000",
          "context": "Sample.Periodic",
          "measurand": "Power.Active.Import",
          "unit": "W"
        }
      ]
    }
  ]
}

Two key levels:

  • meterValue is a list of readings at a point in time. Usually one entry per sampling interval, though a single message can carry several if the charger batches them.
  • sampledValue within each reading is the list of measurands sampled at that timestamp. A charger reporting energy + power + voltage + current would have 4 entries.

Each sampledValue has:

  • value. The measurement, carried as a string.
  • context. Why this reading exists, covered below.
  • format. Raw for a numeric string, or SignedData for a cryptographically signed reading.
  • measurand. What is being measured. Defaults to Energy.Active.Import.Register.
  • phase. Which electrical phase for AC: L1, L2, L3, N, L1-N and so on.
  • location. Where the measurement was taken: Inlet, Outlet, EV, Body, or Cable.
  • unit. kWh, W, V, A, Celsius, Percent.

It is a rich structure that absorbs a lot of variability. The cost of that flexibility is that two implementations can fill it in differently for the same physical reading, and both are technically correct.

flowchart TD
  MV[MeterValues message] --> R1[meterValue<br/>reading at timestamp]
  R1 --> S1[sampledValue<br/>Energy Register]
  R1 --> S2[sampledValue<br/>Power Import]
  R1 --> S3[sampledValue<br/>Voltage per phase]
  S1 --> F[value / context<br/>measurand / unit]
  style MV fill:#1e3a5f,stroke:#2b6cb0,color:#fff

The contexts

The context field tells you why this reading exists. Common values:

  • Sample.Periodic. Routine sampling during a session, and the context most readings carry.
  • Sample.Clock. A reading triggered by the clock, such as on the minute, independent of any transaction.
  • Transaction.Begin. The meter reading at the moment the transaction started. The end meter minus this is the total energy delivered, which makes it a billing anchor.
  • Transaction.End. The meter reading at the moment the transaction stopped, and the other billing anchor.
  • Trigger. A reading sent in response to a TriggerMessage (coming soon) from the CSMS.
  • Other. Vendor-specific, and less common.

The Transaction.Begin and Transaction.End readings are the ones that matter most. Periodic samples are good for dashboards, but the billing math anchors on the begin and end pair, and confusing the two is the root of a surprising share of billing disputes.

The measurands

OCPP defines a long list of possible measurands. The ones most commonly reported:

Energy.Active.Import.Register is the cumulative energy delivered to the EV, in kWh, either for the session or as a lifetime accumulator depending on the charger. This is the measurand billing depends on.

Power.Active.Import is the instantaneous power being delivered, in W.

Voltage is instantaneous voltage, often reported per phase for AC.

Current.Import is instantaneous current, often per phase.

Frequency is grid frequency, 50 Hz across Europe and 60 Hz across North America, and is occasionally useful for power-quality monitoring.

Temperature is in degrees Celsius, and could be the charger body, the inlet, the cable, or a vehicle-reported battery temperature depending on location.

SoC, state of charge, is the battery percentage. It only appears when the vehicle communicates it, via ISO 15118 (coming soon) or a similar mechanism.

Less common but useful:

Energy.Reactive.Import.Register carries reactive energy, which matters for industrial billing.

Power.Reactive.Import is instantaneous reactive power.

Energy.Active.Export.Register and Power.Active.Export carry energy and power flowing from the vehicle, which is what bidirectional charging and V2G depend on.

RPM is only relevant for vehicles that report drivetrain data, which is rare.

Distance is the vehicle odometer, where it is reported at all.

Different chargers report different subsets. A budget AC unit may report Energy.Active.Import.Register and nothing else, while a modern DC fast charger may report a dozen or more measurands per sample. Neither is out of spec, which is precisely the problem.

Sampling configuration

The CSMS controls how often MeterValues fire via configuration variables. Key ones in OCPP 1.6:

  • MeterValueSampleInterval. How often to sample during a session, in seconds. Zero disables periodic sampling. Typical values are 30, 60, or 300.
  • MeterValuesSampledData. A comma-separated list of measurands to sample, for example Energy.Active.Import.Register,Power.Active.Import,Voltage,Current.Import.
  • ClockAlignedDataInterval. How often to send Sample.Clock readings, independent of any transaction. Zero disables them.
  • MeterValuesAlignedData. Which measurands to capture for those clock-aligned readings.
  • StopTxnSampledData. What to sample at transaction end.

In OCPP 2.0.1 the names are slightly different (and tied into the device model) but the concepts are equivalent.

You set these via SetConfiguration in 1.6 or SetVariables in 2.0.1. Defaults vary by OEM. Some hardware arrives sensibly configured and some arrives with everything switched off, so treat metering configuration as a commissioning step rather than an assumption.

Sample intervals: what to choose

A practical guide.

For pure billing: 60 seconds is plenty. Some operators use 300 seconds. You really only need begin + end + occasional snapshots for trust/verification.

For real-time dashboards: 10-30 seconds. Users watching their session in an app want to see the energy counter tick up.

For high-frequency analytics (rare): 1-5 seconds. Only useful for engineering analysis or grid services.

For demand-response participation: depends on the program. Some require 1-second granularity, some accept 1-minute.

Faster sampling means more bandwidth, more storage, and more processing. Work the arithmetic before you choose: 1,000 chargers sampling every 10 seconds across 8 charging hours a day is 2,880 samples per charger per day, or roughly 2.9 million sample events daily. Storage and indexing costs follow directly from that number.

A sensible default: 60-second periodic samples plus Transaction.Begin and Transaction.End. Adjust upward only when there’s a specific need.

The phase tagging issue

For AC three-phase chargers, MeterValues should report per-phase data. The phase field accepts:

  • L1, L2, L3 for individual line phases.
  • N for neutral.
  • L1-N, L2-N, L3-N for line-to-neutral measurements.
  • L1-L2, L2-L3, L3-L1 for line-to-line measurements.

Some chargers report per-phase voltage and current; others only report aggregate / line-to-neutral; some report L1 only and treat it as representative.

Per-phase analytics such as power factor and phase balance need genuine per-phase data, and it cannot be reconstructed after the fact from an aggregate. This is a question to ask during hardware evaluation, because the answer is fixed in firmware by the time the units arrive.

The OCPP 2.0.1 TransactionEvent model

OCPP 2.0.1 changed how meter data flows. Instead of separate MeterValues messages during a transaction, meter readings are embedded inside TransactionEvent messages of type “Updated”:

{
  "eventType": "Updated",
  "transactionInfo": { "transactionId": "abc123" },
  "timestamp": "2026-06-26T19:15:00Z",
  "meterValue": [ ... same structure as 1.6 ... ]
}

The data is identical and only the envelope changed. The benefit is unification, since start, update, end, and energy data all flow through one message type. The cost is that code migrating from 1.6 has to rewire its MeterValues handler rather than rename it. See TransactionEvent in OCPP 2.0.1 for the full model.

OCPP 2.0.1 also adds:

  • Aligned data can flow through TransactionEvent or through a separate MeterValuesRequest, since the standalone message still exists for non-transactional readings.
  • Tariff information can travel alongside meter data, which is what allows a charger to display running cost during a session.

Common operational issues

A list of things that go wrong with MeterValues in production.

Missing measurands. Charger doesn’t report what you expected. Fix at provisioning: set MeterValuesSampledData explicitly per charger model.

Cumulative energy resets. Some chargers reset their session energy counter at session start (giving you 0 at begin, X at end). Some report a lifetime accumulator (so begin is 12000.0, end is 12012.4). Don’t assume one or the other; use both Transaction.Begin and Transaction.End anchors.

Sampling stops mid-session. The charger drops off the network, MeterValues stop for several minutes, then resume. The periodic stream now has a hole in it. Billing must use Transaction.End as ground truth rather than the sum of periodic samples, or you will under-bill by exactly the size of the outage. See Heartbeat and the connection lifecycle for how those drops get detected.

Time precision varies. Some chargers send timestamps to the millisecond. Some only to the second. Don’t depend on sub-second precision for ordering.

Inconsistent units. Spec says kWh for energy and W for power. Some chargers send Wh or kW instead. Validate units on ingest; convert if needed.

Phase aggregation confusion. Charger reports L1 only, you assume it’s three-phase aggregate. Your per-phase analytics are wrong.

Pre-paid metering drift. Some chargers keep an internal pre-paid counter that drifts from the calibrated meter. Billing on the OCPP-reported value then over- or under-charges. Pre-paid fleets need explicit reconciliation against the meter register rather than trust.

Vendor-specific extensions. Some OEMs add custom measurands not in the standard. Your CSMS should accept and ignore unknown measurands gracefully rather than crashing.

Auditability and regulated markets

In jurisdictions with calibration/measurement regulation (Germany’s MessEV, similar elsewhere), MeterValues need to be:

  • Sourced from a calibrated meter inside the charger.
  • Reported with the SignedData format for tamper-evidence.
  • Accompanied by appropriate metadata (calibration date, public key, etc.).

OCPP’s SignedData support covers this. The implementation cost is significant: a proper PKI for the charger’s signing key, back-end signature validation, and an audit trail queryable by a regulator rather than by an engineer. It shares most of its machinery with Profile 3 security, so the two are worth planning together.

For non-regulated markets, regular Raw-format MeterValues are sufficient. Don’t add SignedData complexity unless you need it.

Storage and analytics design

If you’re building a CSMS, the data design around MeterValues matters.

Hot store: recent samples (last 30 days), indexed for per-session queries. PostgreSQL with proper indexes is fine here.

Warm store: aggregated daily/hourly summaries by charger, by session, by tariff. Often a separate analytical store (ClickHouse, BigQuery, Snowflake).

Cold store: raw samples archived for compliance and rare audit needs. S3 or similar object store.

Do not keep raw samples forever in your hot store. Run your own numbers from the sampling arithmetic above, then set a retention policy on purpose rather than discovering one when the disk fills. Aggregate, archive, expire.

Use time-series databases for monitoring. InfluxDB, TimescaleDB, or similar are well-suited for the high-write, time-indexed nature of meter samples.

The honest summary

MeterValues is a message where the specification is fine and the implementations vary enormously. That is the whole difficulty. Nothing here is hard to read in the spec, and almost everything here is hard to rely on across a mixed fleet.

The single most valuable habit is separating the two roles this data plays. Periodic samples are telemetry: useful, lossy, and safe to lose. The Transaction.Begin and Transaction.End readings are the record: they are what a customer is charged against and what a roaming partner reconciles. Teams that treat both as one stream end up billing from telemetry, and telemetry has gaps in it by design.

Set sample intervals from what you actually need rather than what the hardware can do, validate units and measurands at ingest rather than at month-end, and decide your retention policy before your storage bill decides it for you.

Quick check

Q1. Which measurand is the primary field for billing energy delivered?
Q2. Why might summing Sample.Periodic values give a different total than end meter minus start meter?
Q3. How does OCPP 2.0.1 transport meter readings during a transaction?
Q4. What is the recommended way to handle a mid-session gap where MeterValues stopped arriving?
Q5. When is SignedData format for MeterValues genuinely required?

Frequently asked questions

How often should MeterValues fire during a session?

For most billing purposes, every 30-60 seconds is plenty. Some operators sample faster (5-15 seconds) for real-time dashboards. The CSMS controls the interval via configuration (MeterValueSampleInterval in 1.6). Faster means more data, more storage, and more bandwidth, with diminishing returns past roughly 10-second sampling for most use cases.

Which measurands are commonly reported?

Energy.Active.Import.Register (cumulative energy delivered, and the field billing depends on), Power.Active.Import (current power), Voltage and Current per phase, Temperature, and SoC where the vehicle reports it via ISO 15118. Coverage varies widely by hardware: some chargers report a dozen measurands and some report two.

Why does my session show less energy than the meter reading shows?

Usually a reading-context confusion. The total session energy is end-meter minus start-meter, both with context Transaction.Begin and Transaction.End. If you sum Sample.Periodic values you may get a different number because sampling can miss the very start and end of the session.

What is the difference between MeterValues in OCPP 1.6 and TransactionEvent in 2.0.1?

In 1.6, MeterValues is a separate message sent during a transaction. In 2.0.1, meter readings are embedded inside TransactionEvent messages of type Updated. The data is similar; the message envelope is different. The 2.0.1 model is cleaner because all transaction-related events flow through one message type.

Found this useful? Share it.