Skip to content

debounce control-pilot voltage to ignore single-sample glitches#180

Open
czipis wants to merge 1 commit into
dzurikmiroslav:masterfrom
czipis:pilot-debounce
Open

debounce control-pilot voltage to ignore single-sample glitches#180
czipis wants to merge 1 commit into
dzurikmiroslav:masterfrom
czipis:pilot-debounce

Conversation

@czipis

@czipis czipis commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

evse: debounce control-pilot voltage to ignore single-sample glitches

Problem

evse_process() reads the control-pilot voltage once per loop (~50 ms) and acts
on it immediately. On a noisy CP line a single spurious sample is enough to drive
a state transition, so the state machine can flap — e.g. A ↔ B1 every cycle with
no cable connected — repeatedly switching the AC relay, starting/stopping
energy-meter sessions and reconfiguring the status LED:

evse: Enter B1 state
ac_relay: Set relay: 0
energy_meter: Start session
evse: Enter A state
ac_relay: Set relay: 0
energy_meter: Stop session
... (repeats every few hundred ms)

Besides the relay/meter/LED churn, this is what exposed the LED-timer panic fixed
in the companion PR.

Fix

Debounce the pilot voltage in evse_process(): a changed reading must hold for
PILOT_STABLE_SAMPLES consecutive samples before the state machine acts on it.
A single-sample glitch is rejected; a genuine transition is accepted after
PILOT_STABLE_SAMPLES reads. The diode-short check, which uses the separate
pilot_down_voltage_n12 flag, is intentionally left on the raw reading.

PILOT_STABLE_SAMPLES defaults to 3 (~150 ms at the current process cadence).

Trade-off

This adds roughly PILOT_STABLE_SAMPLES × loop_period of latency to legitimate
state changes, including disconnect detection while charging. At the default
(~150 ms) that's fine for typical use and well-behaved; set it to 2 (~100 ms) if
you want faster reaction, or tune to taste. It's a single #define.

Testing

  • Builds clean with ESP-IDF v6.0.1 (ESP32).
  • With the debounce, a noisy/floating CP line no longer flaps the state machine;
    the relay/meter/LED churn above disappears.

Notes

The root noise is hardware-side (CP front-end), but the firmware shouldn't thrash
on a single bad sample. This pairs naturally with the LED-timer crash fix; happy
to squash them into one "robustness on a noisy pilot" PR if preferred.

Checklist:

  • The pull request is done against the latest master branch
  • The code change compiles without warnings
  • The code change are formatted (clang-format)
  • New and existing unit tests pass

Plase set Github secret WOKWI_CLI_TOKEN to run CI unit test in Wokwi simulator (https://docs.wokwi.com/wokwi-ci/github-actions)

NOTE: The code change must pass CI. Your PR cannot be merged unless CI pass

@dzurikmiroslav

Copy link
Copy Markdown
Owner

Thanks for your interest.

I was working on similar functionality in pilot.c. My goal was to reduce ADC measurement noise by using multi-sampling of the CP voltage. At the moment I'm testing with 3 samples. I also applied the same approach to the pilot_down_voltage_n12 measurement (-12V on the CP line).

Just for transparency, I'd like to ask whether any AI tools were used in preparing this pull request. I'd just like to understand to what extent the code was AI-generated or AI-assisted.

@czipis

czipis commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

yes, all my current PRs were AI-generated with Anthropic's Claude Opus 4.7 during several iterations with on the evse device testing and reporting the behaviour back to AI to fix and final AI review

@czipis czipis force-pushed the pilot-debounce branch 2 times, most recently from d0b81f9 to 76856d1 Compare June 5, 2026 14:28
`evse_process()` reads the control-pilot voltage once per loop (~50 ms) and acts
on it immediately. On a noisy CP line a single spurious sample is enough to drive
a state transition, so the state machine can flap — e.g. `A ↔ B1` every cycle with
**no cable connected** — repeatedly switching the AC relay, starting/stopping
energy-meter sessions and reconfiguring the status LED:

```
evse: Enter B1 state
ac_relay: Set relay: 0
energy_meter: Start session
evse: Enter A state
ac_relay: Set relay: 0
energy_meter: Stop session
... (repeats every few hundred ms)
```

Besides the relay/meter/LED churn, this is what exposed the LED-timer panic fixed
in the companion PR.

Debounce the pilot voltage in `evse_process()`: a *changed* reading must hold for
`PILOT_STABLE_SAMPLES` consecutive samples before the state machine acts on it.
A single-sample glitch is rejected; a genuine transition is accepted after
`PILOT_STABLE_SAMPLES` reads. The diode-short check, which uses the separate
`pilot_down_voltage_n12` flag, is intentionally left on the raw reading.

`PILOT_STABLE_SAMPLES` defaults to `3` (~150 ms at the current process cadence).

This adds roughly `PILOT_STABLE_SAMPLES × loop_period` of latency to legitimate
state changes, **including disconnect detection while charging**. At the default
(~150 ms) that's fine for typical use and well-behaved; set it to `2` (~100 ms) if
you want faster reaction, or tune to taste. It's a single `#define`.

- Builds clean with ESP-IDF **v6.0.1** (ESP32).
- With the debounce, a noisy/floating CP line no longer flaps the state machine;
  the relay/meter/LED churn above disappears.

The root noise is hardware-side (CP front-end), but the firmware shouldn't thrash
on a single bad sample. This pairs naturally with the LED-timer crash fix; happy
to squash them into one "robustness on a noisy pilot" PR if preferred.
@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants