-
-
Notifications
You must be signed in to change notification settings - Fork 133
Description
Brief summary of the bug
PressureController.cpp lines 244 and 251 divide by (1 - P / _maxPressure). When pressure reaches 15 bar, this evaluates to division by zero, producing infinity/NaN values that corrupt pump control output. Since the pressure sensor is mounted at the pump outlet, 15 bar is reachable during normal operation.
Describe the issue in greater detail
Found during code review of lib/NayrodPID/src/PressureController/PressureController.cpp.
Vulnerable code (lines 244 and 251):
// Line 244
float Ki = _integralGain / (1 - P / _maxPressure);
// Line 251
float K = _commutationGain / (1 - P / _maxPressure) * Qa / Ceq;Where _maxPressure is defined (PressureController.h line 70):
const float _maxPressure = 15.0f; // Maximum pressure (bar)What happens when P = 15.0 bar:
1 - P / _maxPressure = 1 - 15.0/15.0 = 0.0
Ki = _integralGain / 0.0 = inf
K = _commutationGain / 0.0 * ... = inf
These infinity values propagate through the calculation:
// Line 252
_pumpDutyCycle = Ceq / Qa * (...) - iterm; // iterm contains infThe final clamp (line 263) produces unpredictable results:
std::clamp(inf, 0, 100)→ 100 (pump full blast)std::clamp(-inf, 0, 100)→ 0 (pump stops)std::clamp(nan, 0, 100)→ undefined
Why 15 bar is reachable during normal operation:
The GaggiMate Pro uses a 0-1.6 MPa (16 bar) pressure transducer installed at the pump outlet, between the pump and the 3-way solenoid valve. This location sees full pump pressure, not post-OPV extraction pressure.
The Ulka vibration pump in a Gaggia Classic is rated for ~15 bar maximum output. At the pump outlet, 15 bar can be reached during:
- Pressure profile ramp-up — Aggressive profiles targeting 12-14 bar can overshoot or experience sensor noise that spikes to 15 bar
- Valve transitions — When the solenoid valve closes during a shot, the pump momentarily sees full back-pressure
- Preinfusion phases — Some profiles deliberately push high pressure before backing off
- Transient blockages — Brief flow restrictions cause pressure spikes
This is not an edge case requiring equipment failure — it's a boundary condition reachable during normal pressure profiling.
When pressure hits exactly 15 bar:
- Pump output becomes erratic — Jumps instantly to 100% or drops to 0%, disrupting the shot in progress
- Pressure profile fails mid-shot — A carefully tuned profile goes haywire at the worst possible moment
- Potential pressure spike — If pump goes to 100% while pressure is already at 15 bar, it's pushing maximum force into an already high-pressure system
- Confusing diagnostics — User sees pump misbehave and doesn't know if it's the puck, the profile, or the controller
Suggested fix:
float pressureRatio = P / _maxPressure;
float denominator = fmaxf(1.0f - pressureRatio, 0.01f); // Clamp to minimum 0.01
float Ki = _integralGain / denominator;Are you able to reproduce the issue?
No
Steps to reproduce
- Create a pressure profile that targets 12-14 bar
- Run the profile with a fine grind that creates high resistance
- Monitor for pressure spikes to 15 bar (sensor noise, overshoot, or valve transitions)
- Observe pump output becomes erratic when pressure hits exactly 15 bar
Expected behavior
When pressure approaches the maximum, the controller should gracefully limit its gain rather than producing infinity/NaN values. The pump output should remain stable and controlled.
Has this function/fetaure worked before with your GaggiMate?
No
Relevant logs or error messages
N/A — ESP32 float division by zero doesn't throw an exception. It silently returns inf/nan which propagates through calculations.Firmware version
Code review performed on current master branch
What machine are you experiencing this issue on?
N/A — affects all GaggiMate Pro configurations using pressure profiling
Additional context
CWE-369 (Divide By Zero). The pressure sensor is mounted at the pump outlet per installation instructions, where it sees full pump pressure (up to 15 bar) rather than post-OPV extraction pressure. The gain scheduling formula 1/(1 - P/Pmax) is mathematically undefined at the boundary. This is a latent bug that will trigger whenever pressure reaches exactly 15 bar during normal pressure profiling operations.