OCPP MESSAGE · UPDATED 11 AUG 2026

MeterValues: the numbers billing runs on

Every kilowatt-hour a driver pays for, every progress bar in an app, every time-of-use price boundary — all of it comes from this message. It is also the highest-volume message on any charging network, which makes its configuration a genuine engineering trade-off.

PART OF THE OCPP COMPLETE GUIDE · 14 MESSAGE GUIDES

IN ONE PARAGRAPH

MeterValues streams meter samples during a session. Each sample carries a measurand saying what was measured, a context saying why the sample was taken, and a unit. The cumulative energy register is what billing depends on; everything else is telemetry. Sampling interval trades billing granularity against data volume across the fleet.

The message

// Charge point -> CSMS
[2, "19223208", "MeterValues", {
  "connectorId": 1,
  "transactionId": 770142,
  "meterValue": [{
    "timestamp": "2026-08-11T09:47:10Z",
    "sampledValue": [
      { "value": "4490220", "context": "Sample.Periodic",
        "measurand": "Energy.Active.Import.Register",
        "location": "Outlet", "unit": "Wh" },
      { "value": "48200",   "context": "Sample.Periodic",
        "measurand": "Power.Active.Import", "unit": "W" },
      { "value": "74",      "context": "Sample.Periodic",
        "measurand": "SoC", "unit": "Percent" },
      { "value": "398.2",   "context": "Sample.Periodic",
        "measurand": "Voltage", "phase": "L1-N", "unit": "V" }
    ]
  }]
}]

// CSMS -> charge point
[3, "19223208", {}]

transactionId is optional. Samples can be sent outside a transaction — an idle charger reporting voltage, for instance — and those must not be attributed to any session. A platform that assumes every MeterValues belongs to a transaction will mis-bill.

Measurands

MeasurandIsMatters for
Energy.Active.Import.RegisterCumulative energy from the grid, in WhBilling. This is the one that matters.
Power.Active.ImportInstantaneous power drawLive progress, load management
Current.ImportCurrent drawDiagnostics, phase balance
VoltageSupply voltagePower quality, fault diagnosis
SoCVehicle state of charge, percentDriver UX — only if the car reports it
TemperatureComponent temperatureThermal derating and fault prediction
Energy.Active.Export.RegisterEnergy returned to the gridV2G
Energy.Active.Import.Register is cumulative, like an odometer. A reading of 4,490,220 Wh does not mean 4.49 MWh in this session — it is the meter's lifetime total. Session energy is always a difference between two readings. Treating a register value as session energy produces invoices in the thousands of kWh, and it is the most costly arithmetic error in EV charging.

SoC is worth a note: it comes from the vehicle over the charging protocol, not from the charger. Many vehicles do not report it, especially over AC. Build the UI so that a missing state of charge degrades gracefully rather than showing 0%.

Context: why the sample was taken

ContextTaken because
Sample.PeriodicRoutine interval — the bulk of traffic
Sample.ClockClock-aligned interval, e.g. on the hour
Transaction.BeginSession start — the billing baseline
Transaction.EndSession end — the billing close
Interruption.Begin / Interruption.EndCharging paused and resumed
TriggerRequested via TriggerMessage
OtherVendor-specific

Transaction.Begin and Transaction.End samples are the ones to trust for billing boundaries. They should agree with meterStart and meterStop on the transaction messages — and when they do not, you have a data integrity problem worth investigating before you invoice.

Sampling interval: the real trade-off

Controlled by MeterValueSampleInterval in configuration. The choice is not free in either direction.

IntervalSamples per hour per sessionConsequence
10 s360Excellent granularity; heavy data cost and ingestion load
60 s60The usual balance
300 s12Cheap; poor resolution across tariff boundaries
900 s4Billing-boundary risk on time-of-use tariffs

The billing consequence is specific. If a tariff changes price at 22:00 and your last sample before it was at 21:52, the energy consumed in those eight minutes has to be attributed to one side or the other — and whichever you choose, you and your roaming partner may choose differently. Sampling finer than your narrowest tariff boundary is what avoids that argument.

Also configure MeterValuesSampledData deliberately: it decides which measurands are sent. A charger configured without the cumulative energy register produces sessions you cannot bill at all.

Validation

Meter data is the input to money, so validate it on arrival rather than at invoice time:

CheckRuleA failure means
MonotonicityThe cumulative register must never decreaseMeter reset, replacement, or corrupt data
Plausible rateEnergy delta ÷ time must not exceed the connector ratingBad reading or wrong unit
Unit sanityWh vs kWh — a 1000× jump is a unit bugVendor implementation difference
Timestamp orderingSamples should advanceClock drift — see Heartbeat
Transaction linkagetransactionId matches a known sessionOrphan samples, or an untracked session

A decreasing register is the one to alert on immediately. It means the meter was reset or replaced, and every energy calculation spanning that point is wrong until someone establishes a new baseline.

Reconciliation

Three checks that should run continuously on any billing platform:

  • MeterValues against StopTransaction. The last sample should closely match meterStop. A persistent gap means samples are being lost.
  • Sum of deltas against the overall difference. They should agree; disagreement points to duplicated or missing samples.
  • Session energy against the OCPI CDR. If your CDR does not match your own meter data, the CDR is wrong — and a roaming partner's dispute will be decided on exactly this comparison.

Production lessons

  • Treat the energy register as cumulative. Always compute differences, never read a register as session energy.
  • Sample finer than your narrowest tariff boundary.
  • Verify MeterValuesSampledData at commissioning for every charger model.
  • Alert on non-monotonic registers immediately.
  • Handle samples with no transactionId without attributing them to a session.
  • De-duplicate against transactionData delivered on StopTransaction, or offline sessions double-count.
  • Store raw samples, not just derived totals. A billing dispute is resolved from the samples.
  • Stagger clock-aligned sampling across the fleet or every charger reports simultaneously.

Frequently asked questions

What is Energy.Active.Import.Register in OCPP?

The cumulative energy imported from the grid, in watt-hours — a lifetime meter total, like an odometer. Session energy is always the difference between two readings. Treating a register value as session energy produces invoices in the thousands of kWh.

How often should OCPP MeterValues be sampled?

Sixty seconds is the usual balance. The binding constraint is that you should sample finer than your narrowest tariff boundary, otherwise energy consumed between the last sample and a price change has to be attributed arbitrarily — and your roaming partner may attribute it differently.

What does the context field in a sampled value mean?

Why the sample was taken — Sample.Periodic for routine intervals, Sample.Clock for clock-aligned samples, Transaction.Begin and Transaction.End for billing boundaries, and Interruption.Begin or Interruption.End when charging pauses and resumes.

Why is state of charge sometimes missing from OCPP MeterValues?

Because SoC comes from the vehicle over the charging protocol, not from the charger. Many vehicles do not report it, particularly over AC, so the UI should degrade gracefully rather than displaying zero.

What should you do if the meter register decreases?

Alert immediately. A decreasing cumulative register means the meter was reset or replaced, and every energy calculation spanning that point is wrong until a new baseline is established.