fix(render): clear display and reset graphs on new telemetry session - #31
Merged
Conversation
Addresses #30. The render loop relied solely on Ratatui's diff rendering and only cleared the terminal twice (entering Debug from loading, and on the first telemetry frame). Any display pixel corrupted by a transient SPI glitch was therefore never repaired, so artifacts accumulated until reboot. Introduce a session model: when telemetry resumes after the machine has been offline (no UART frame for MACHINE_OFFLINE_TIMEOUT = 30s) or on the first frame, treat it as a new session and request a full terminal clear, which heals accumulated artifacts. The clear is now driven by a `needs_terminal_clear` flag on GlobalAppState that the state machine sets and the render loop drains, replacing the scattered `terminal.clear()` calls in both the device and simulator loops. `MachineState::reset_session()` also clears the graph buffers (so the chart restarts instead of jumping down from stale data) and drops `last_frame`/`shot_started_at` so the resuming frame is treated as a fresh start and cannot emit phantom mode/shot events (which would otherwise reach MQTT and miscount cups in Home Assistant). UX fixes bundled in: - When the backlight has timed out, the first button press only wakes the backlight and no longer also switches screens. - Telemetry staleness now drives the UI: once the machine is offline the waiting screen (rat + "waiting for machine...") is shown again, via a new `GlobalAppState::machine_online()` helper used by draw() and render_image(). Tests: add coverage for wake-on-first-press and session reset (buffer clear plus absence of phantom events); update the existing short-press test for the new backlight gating.
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.
Closes #30.
Problem
The render loop relied solely on Ratatui's diff rendering and only cleared the terminal twice (entering Debug from loading, and on the first telemetry frame). Any display pixel corrupted by a transient SPI glitch (EMI / ground noise, most likely when the machine switches its relay/heater) was therefore never repaired — Ratatui's previous-buffer still considered the cell correct — so artifacts accumulated until reboot.
Approach
Introduce a session model: when telemetry resumes after the machine has been offline (no UART frame for
MACHINE_OFFLINE_TIMEOUT = 30s) or on the first frame, treat it as a new session and request a fullterminal.clear(), which heals accumulated artifacts at the natural boundary (machine turned back on).The clear is now driven by a
needs_terminal_clearflag onGlobalAppStatethat the state machine sets and the render loop drains, replacing the scatteredterminal.clear()calls in both the device and simulator loops (also clears on Debug toggle).MachineState::reset_session()clears the graph buffers (so the chart restarts instead of jumping down from stale data) and dropslast_frame/shot_started_at, so the resuming frame is treated as a fresh start and cannot emit phantom mode/shot events (which would otherwise reach MQTT and miscount cups in Home Assistant).Bundled UX fixes
GlobalAppState::machine_online()helper used bydraw()andrender_image(). Once the machine is offline the waiting screen (rat + "waiting for machine...") is shown again, instead of a frozen Dashboard.Tests
test_press_while_dark_only_wakes_backlight— first press wakes, second switches.test_telemetry_resume_starts_new_session— buffers reset to a single fresh sample and no phantom events on resume.test_handle_button_press_shortfor the new backlight gating.All 37 tests pass;
cargo clippyclean on the simulator build.Verification in simulator (
cargo sim)Note: the SPI/EMI corruption itself can't be reproduced in the simulator, but the session-start self-healing (the core fix) is exercised there.