A charging invoice is one subtraction: meter at stop minus meter at start. Everything else is presentation. Which is why it is remarkable how many platforms compute the amount from something else — elapsed time multiplied by reported power, or a running total accumulated in application memory — and then cannot explain a disputed bill.
Store the readings, not the total
The session record should carry the actual meterStart and meterStop values as the charger reported them, permanently, alongside the derived energy. When a driver disputes a session eight months later, those two numbers are the evidence. A stored total is an assertion.
Keep the intermediate MeterValues too. They are what tells you the shape of the session — whether the vehicle tapered, whether the charger derated, whether there was a gap in the middle where nothing was delivered.
What to sample, and how often
| Measurand | Why | Interval |
|---|---|---|
| Energy.Active.Import.Register | The billing number — non-negotiable | Every 60s |
| Power.Active.Import | Derating and taper detection | Every 60s |
| SoC | Driver experience, taper explanation | Where the vehicle reports it |
| Current and voltage | Diagnosing poor delivery | Every 60s where cheap to carry |
| Temperature | Thermal derating | Where available |
Sixty seconds is a reasonable default. Shorter intervals multiply storage across a network without improving the invoice, since the invoice depends only on the endpoints. Longer intervals lose the diagnostic value.
The rounding rule
Round once, at the end. Compute the energy delta at full precision, apply the rate at full precision, then round the final amount to two decimals. Rounding at each intermediate step introduces drift that is small per session, systematic across a network, and impossible to explain to a site partner reconciling a settlement.
Missing and impossible values
Chargers send readings that go backwards, jump implausibly, or stop arriving mid-session. Each needs a defined handling rather than an exception in a log:
- A decreasing register almost always means the meter reset. Treat the session as unbillable and flag it rather than computing a negative.
- A delta larger than the connector could physically have delivered in the elapsed time is impossible. Cap it, flag it, and do not bill it silently.
- No meterStop — the charger disconnected before reporting — means falling back to the last MeterValues reading, and recording that you did.
- Every one of these should reach a queue. A session that cannot be billed correctly is a defect, and defects that only exist in logs are defects nobody fixes.
The test
Pick a completed session at random and reconstruct the invoice from stored values alone — meter start, meter stop, the tariff snapshot, the tax rule. If you can do that without querying anything else, the billing is trustworthy. If you cannot, it is trustworthy only until somebody checks.