Skip to content

METER_VALUE_ANOMALY false positives: monotonicity is checked across all measurands at once #127

Description

@shiv3

detectMeterValueAnomaly (rule 14) flattens every sampledValue in a session into a single
readings[] array and then asserts that the sequence never decreases. measurand, phase,
unit, location and connectorId are all ignored.

dist/core/detection.js (0.4.0), abridged:

for (const mv of meterValues) {
  for (const sv of mv?.sampledValue ?? []) {
    readings.push({ eventId: event.id, value: Number.parseFloat(sv.value) });
  }
}
...
for (let i = 1; i < readings.length; i++) {
  if (readings[i].value < readings[i - 1].value) { /* METER_VALUE_ANOMALY */ }
}

Only cumulative registers (Energy.*.Register) are monotonic by OCPP 1.6 §7.28. Power.Active.Import,
SoC, Current.Import, Voltage, Temperature, RPM etc. all legitimately rise and fall, so any
charge point that reports more than one measurand per sample produces a warning on nearly every
MeterValues message.

Reproduction

A perfectly well-behaved 3 kW session sending the two most common measurands:

{"connectorId":3,"transactionId":1987,"meterValue":[{"timestamp":"...","sampledValue":[
  {"measurand":"Energy.Active.Import.Register","value":"600","unit":"Wh","context":"Sample.Periodic"},
  {"measurand":"Power.Active.Import","value":"3000","unit":"W","context":"Sample.Periodic"}]}]}

The energy register over the session is 600, 625, 650, 675, ... 1150 Wh — +25 Wh per 30 s, exactly
3 kW, strictly monotonic. But because the constant 3000 W power sample is interleaved into the same
series, the flattened list reads 600, 3000, 625, 3000, 650, ... and 22 of the 23 MeterValues
messages are reported as:

Non-monotonic meter reading: value decreased from 3000 to 625 in session session-0 (transaction 1987)

A real 12-minute single-connector session produced 22 METER_VALUE_ANOMALY warnings, all false.

Second, related problem: no per-connector grouping

connectorId appears exactly once in detection.js (in a comment). On a multi-connector station,
readings from different connectors — each with its own independent meter — land in the same series,
so e.g. connector A's 6000 followed by connector B's 100 is also reported as a decrease. On a
4-connector trace we saw 80 such warnings.

The same missing grouping affects STATUS_TRANSITION_VIOLATION: connector A going Available while
connector B goes Finishing is flagged as an invalid transition. (Happy to split that into its own
issue if you'd prefer.)

Suggested fix

Bucket readings by (connectorId, measurand, phase, unit, location) and only apply the monotonicity
check to cumulative measurands — Energy.Active.Import.Register, Energy.Reactive.Import.Register,
Energy.Active.Export.Register, Energy.Reactive.Export.Register (per 1.6 the default measurand when
the field is absent is Energy.Active.Import.Register, so a missing measurand should still be
treated as cumulative). Non-cumulative measurands should be skipped by this rule entirely; the
negative-value check can stay as-is for measurands where negative is out of range, but note that
Power.Active.Import and Current.Import can legitimately be negative on a bidirectional (V2G)
charger.

Workaround

Downstream consumers currently have to drop METER_VALUE_ANOMALY and re-derive it, or pre-split the
trace per connector before handing it to the toolkit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions