Skip to content

OCPP: sessions occasionally persisted with meterStart=null and chargedEnergy equal to the lifetime meter reading (Alfen Eve Single Pro) #29374

@pellenbeck

Description

@pellenbeck

Describe the bug

On an Alfen Eve Single Pro (OCPP 1.6J, single connector), evcc occasionally persists a charging session with:

  • meterStart: null
  • chargedEnergy ≈ the wallbox's lifetime Energy.Active.Import.Register reading (several thousand kWh)

As a result, all aggregated statistics (daily/monthly/yearly totals, cost, CO₂) become unusable because a single session contributes ~8 MWh.

This has happened three times in four weeks. The installation was switched from Modbus to OCPP four weeks ago; under Modbus the same wallbox never produced corrupt session data.

Affected sessions (GET /api/sessions):

id	created	chargedEnergy (kWh)	meterStart	meterStop
367	2026-03-30 09:38	7 783.903	null	7 783.903
380	2026-04-02 12:51	7 825.248	null	7 825.248
409	2026-04-23 09:17	7 930.179	null	7 912.760

Current lifetime Energy.Active.Import.Register of the wallbox at the time of writing: 7 930 237 Wh — i.e. all three corrupted chargedEnergy values match the wallbox's absolute lifetime meter reading at the time the session ended.

Note for id 409: chargedEnergy (7930.179) > meterStop (7912.760) — so chargedEnergy is not simply meterStop − 0; it comes from a different accumulation path.

Two parallel meter series in the DB
Across 400+ sessions there are two independently growing meter series in meterStart/meterStop. The OCPP trace only ever shows one Energy.Active.Import.Register stream (single measurand, location: "Outlet", no duplicates), which grows around the ~7 900 kWh mark. The second series around ~4 900 kWh does not appear in any OCPP frame — evcc seems to accumulate it internally (likely from Power.Active.Import × Δt) and then writes it into the same session fields as the real meter reading. Example (sessions 371–378, in chronological order):

id=371  meterStart=4944.257  meterStop=4944.356    # internal series
id=372  meterStart=7786.260  meterStop=7793.713    # Alfen meter
id=374  meterStart=7793.969  meterStop=7794.487    # Alfen meter
id=375  meterStart=4944.372  meterStop=4950.589    # internal series
id=376  meterStart=7794.723  meterStop=7809.332    # Alfen meter
id=377  meterStart=4963.570  meterStop=4963.921    # internal series
id=378  meterStart=7809.332  meterStop=null        # Alfen meter, StopTransaction lost

Both series progress monotonically for months, so evcc is clearly persisting two different sources into the same columns without distinguishing their origin.

Also: out of 392 sessions, 16 (~4 %) have at least one null meter field, and the frequency is growing over time.

Suspected trigger: startup measurand probing rewrites MeterValuesSampledData
The OCPP trace at startup shows evcc sending seven sequential ChangeConfiguration requests that each overwrite the charger's entire MeterValuesSampledData with a single measurand, and only at the end restores the full list:

send ChangeConfiguration MeterValuesSampledData=Power.Active.Import
send ChangeConfiguration MeterValuesSampledData=Energy.Active.Import.Register
send ChangeConfiguration MeterValuesSampledData=Current.Import
send ChangeConfiguration MeterValuesSampledData=Voltage
send ChangeConfiguration MeterValuesSampledData=Current.Offered
send ChangeConfiguration MeterValuesSampledData=Power.Offered
send ChangeConfiguration MeterValuesSampledData=SoC
send ChangeConfiguration MeterValuesSampledData=Power.Active.Import,Energy.Active.Import.Register,Current.Import,Voltage,Current.Offered

Before this probing starts, the charger already reports its MeterValuesSampledData correctly configured as Power.Active.Import,Energy.Active.Import.Register,Current.Import,Voltage,Current.Offered in GetConfiguration. The probing is therefore unnecessary, and during the window in which MeterValuesSampledData is transiently set to e.g. only SoC or Power.Offered, any MeterValues the charger sends contains no Energy.Active.Import.Register.

If a session's StartTransaction (or the first subsequent MeterValues) falls into that window, evcc gets no valid meter reading to use as meterStart. On StopTransaction the charger then delivers the lifetime Energy.Active.Import.Register reading (as required by its StopTxnSampledData=Energy.Active.Import.Register configuration), and evcc appears to store that lifetime value as chargedEnergy / meterStop without validating that a valid meterStart was captured.

Expected behavior

  • evcc should not clobber MeterValuesSampledData at startup when the charger already reports the desired -measurands as configured. If probing is still needed, it should either
    -- try the full list in one request and fall back measurand-by-measurand only on Rejected, or
    -- restore the original configured list immediately after each probe, or
    -- be skipped entirely when GetConfiguration shows the desired measurands are already present.
  • If meterStart for a session cannot be determined, chargedEnergy must be computed strictly from Power × Δt (bounded by session duration × max charger power), never from an absolute meter reading.
  • Per charger, evcc should use a single, well-defined meter source (OCPP meter or internal integration) so both cannot end up in the same meterStart/meterStop columns.
  • A sanity check before persisting — e.g. chargedEnergy ≤ connectorMaxPower × sessionDuration × 1.1 and < 300 kWh for a single AC session — would have prevented all three catastrophic records here.

Steps to reproduce

Not reliably reproducible on demand. The pattern over 400+ sessions is:

  1. Run evcc against an Alfen Eve Single Pro over OCPP 1.6J, with the default Power.Active.Import,Energy.Active.Import.Register,Current.Import,Voltage,Current.Offered measurand set.
  2. Restart evcc (e.g. docker image update) occasionally.
  3. After some number of restarts, a session is persisted with meterStart: null and chargedEnergy ≈ the wallbox's lifetime meter reading.

Configuration details

Configuration is done entirely through the evcc web UI (native OCPP integration). No custom evcc.yaml overrides for the charger. The charger is a single OCPP charge point at connector 1, meterinterval: 10s, default measurands. One loadpoint in pv mode.

Log details

Excerpt of the startup trace showing the probing behaviour and a subsequent normal MeterValues frame (identifying fields redacted):

text
[ocpp] TRACE recv: [3,"…",{"configurationKey":[
  … ,
  {"key":"MeterValuesAlignedData","readonly":false,"value":""},
  {"key":"MeterValueSampleInterval","readonly":false,"value":"10"},
  {"key":"MeterValuesSampledData","readonly":false,
   "value":"Power.Active.Import,Energy.Active.Import.Register,Current.Import,Voltage,Current.Offered"},
  {"key":"StopTxnSampledData","readonly":false,"value":"Energy.Active.Import.Register"},
  {"key":"StopTxnAlignedData","readonly":false,"value":"Energy.Active.Import.Register"},
  {"key":"MeterValuesSampledDataMaxLength","readonly":true,"value":"9"},
  {"key":"OCPPStackVersion","readonly":true,"value":"7.1"},
  …
]}]
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Power.Active.Import
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Energy.Active.Import.Register
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Current.Import
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Voltage
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Current.Offered
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Power.Offered
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=SoC
[ocpp] TRACE send: ChangeConfiguration MeterValuesSampledData=Power.Active.Import,Energy.Active.Import.Register,Current.Import,Voltage,Current.Offered

[ocpp] TRACE recv: MeterValues
  {"timestamp":"2026-04-23T19:46:21Z","sampledValue":[
    {"value":"0.000",      "measurand":"Power.Active.Import",            "location":"Outlet","unit":"W"},
    {"value":"7930237.000","measurand":"Energy.Active.Import.Register",  "location":"Outlet","unit":"Wh"},
    {"value":"0.000",      "measurand":"Current.Import","phase":"L1",    "location":"Outlet","unit":"A"},
    {"value":"0.000",      "measurand":"Current.Import","phase":"L2",    "location":"Outlet","unit":"A"},
    {"value":"0.000",      "measurand":"Current.Import","phase":"L3",    "location":"Outlet","unit":"A"},
    {"value":"239.470",    "measurand":"Voltage","phase":"L1-N",         "location":"Outlet","unit":"V"},
    {"value":"241.990",    "measurand":"Voltage","phase":"L2-N",         "location":"Outlet","unit":"V"},
    {"value":"240.560",    "measurand":"Voltage","phase":"L3-N",         "location":"Outlet","unit":"V"},
    {"value":"0.000",      "measurand":"Current.Offered",                "location":"Outlet","unit":"A"}
  ]}
The charger therefore reports a single, well-formed Energy.Active.Import.Register (single measurand, location: "Outlet", no phase, no duplicates) and already has the correct MeterValuesSampledData list configured before evcc starts probing.

I can provide the full trace (including the StartTransaction / StopTransaction for the next corrupt session) on request.

What type of operating system or environment does evcc run on?

Linux

External automation

  • I have made sure that no external automation like HomeAssistant or Node-RED is active or accessing any of the mentioned devices when this issue occurs.

Nightly build

  • I have verified that the issue is reproducible with the latest nightly build

Version

0.305.1

Metadata

Metadata

Assignees

Labels

devicesSpecific device support

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions