Harden safety paths: sensor fail-safe, monotonic time, structured logging - #24
Merged
Merged
Conversation
…ging Address several code-review findings, focused on the fire-control paths. Safety fixes: - Sear mode now turns the blower on before feeding the auger. Previously a Sear entered from a cold blower (e.g. straight after Ready with a warm firepot) could feed pellets with no combustion air. - FireMinder fails safe to Error on a sustained invalid grill reading during a cook, instead of interpreting the -1 "unplugged" sentinel as a dying fire and running the aggressive recovery feed blind. - Display disposes the LCD and driver before the I2C bus they write through, matching Init's teardown order (the old order could throw on shutdown). Correctness: - GetFireCheckTemp uses floating-point proportional math (5/6 of setpoint). The old integer `SetPoint / 180` collapsed to a step function with a ~30F cliff in the threshold at setpoint 360. Robustness: - Duration measurements in Smoker (shutdown cooldown), FireMinder (igniter/ fire/debounce timeouts) and SmokerPid (dt) now use a monotonic TimeProvider clock, so an NTP step on the RTC-less Pi can't spuriously trip or hang a timeout. Wall time is kept only for status display. - Replaced Debug.WriteLine/Console.WriteLine with ILogger across Smoker, FireMinder, SmokerPid, DisplayUpdater and RtdArray, wired through DI. Debug traces were compiled out of the Release builds the deploy ships, leaving the controller nearly silent in journald. - Mode and Fire Minder loops back off briefly after an exception so a persistently-throwing iteration can't hot-spin the CPU. Tests: - FireMinder tests migrated to FakeTimeProvider; added coverage for the sensor-fault fail-safe and the fire-check-temp continuity across setpoint 360. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012nMVayWzPQkxynui9ZwDVB
|
🚀 The Update (preview) for CamSoper-org/inferno-deploy/main (at f6fe2ca) was successful. Resource Changes Name Type Operation
+- restart-api command:remote:Command replaced
+- publish-api command:local:Command replaced
|
Longer PID period per Hold iteration; run/wait split still scales with the PID duty cycle. Also lengthens the minimum-feed cycle Sear uses when the grill is over the max temp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012nMVayWzPQkxynui9ZwDVB
CamSoper
marked this pull request as ready for review
July 5, 2026 03:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements a batch of code-review findings, concentrated on the fire-control paths where a bug has physical consequences. All 76 tests pass (Debug and Release build clean).
Safety fixes
Smoke()andHold()both turn the blower on before running the auger, but theSear()main path did not. A Sear entered from a cold blower (e.g. straight afterReadywith a still-warm firepot, where the fire-started/establish gates can pass immediately) could feed pellets into residual embers with no combustion air. Added_blower.On()on the main sear path.RtdArraydrains toNaNafter a sustained sensor failure and theSmokersurfaces that as-1. FireMinder was consuming-1as a real temperature — below the check temp, so after the debounce it declared the fire unhealthy and ran the aggressive ~75%-duty recovery feed blind. It now counts consecutive invalid readings during a cook and fails safe toError(fuel + igniter cut, blower clears the firepot).Dispose()freed the I2C bus before the LCD/driver that write through it on teardown; reordered to LCD → driver → I2C, matchingInit().Correctness
GetFireCheckTempinteger division.SetPoint - (SetPoint / 180 * 30)is integer math:SetPoint / 180is1across 180–359 and2at 360+, so the fire-health threshold was a step function with a ~30 °F cliff at setpoint 360. Replaced with the intended proportional curve (5/6of setpoint — a 30 °F margin at the 180 °F floor). Added a regression test pinning continuity across 360.Robustness
Smoker), igniter/fire/debounce timeouts (FireMinder), and PIDdt(SmokerPid) — now use an injectedTimeProviderand monotonicGetTimestamp/GetElapsedTime. The RTC-less Pi steps its wall clock when NTP syncs (plausibly during startup ignition); a forward step could previously fire a 10-minute timeout instantly, a backward step could hang it. Wall time is retained only for the status display fields.Debug.WriteLine/Console.WriteLinewithILogger<T>acrossSmoker,FireMinder,SmokerPid,DisplayUpdater, andRtdArray, wired through DI inProgram.cs.Debug.WriteLineis compiled out of the Release builds the deploy ships, so the entire mode/fire narrative was previously absent from journald.Tests
Func<DateTime>clock toFakeTimeProvider.🤖 Generated with Claude Code
https://claude.ai/code/session_012nMVayWzPQkxynui9ZwDVB
Generated by Claude Code