feat(crow_alarm_panel): raw bit-trace logging, arm/disarm retry, time-glitch recovery - #10
Merged
Conversation
Captures every clock-sampled DAT bit (post glitch-filter, same bits the frame parser feeds into boundary_buffer_) into a batched 128-bit string, independent of frame decoding, so mis-alignment/framing issues can be diagnosed by hand from the literal bitstream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Six independent traced sessions (logs-10/35, logs-12/37, logs-42, logs-24/25/26) show a watchdog timeout in CODE_DIGIT_PENDING/ CODE_ENTER_PENDING reliably means the panel's state never changed, with monitor cross-checks confirming no ARMED_STATE broadcast was ever missed. Unlike output-select/zone-bypass, a blind retry here can't undo a change that already landed, so the watchdog now retries the whole sequence (up to ARM_DISARM_MAX_RETRIES=5, covering the worst observed streak) before falling back to the existing abort/restore behavior. Full trace analysis in docs/protocol_trace_2026-08-05_disarm_after_arm.md.
A disarm hit the familiar two-failure-then-success shape, but this time the watchdog's automatic retry resolved it in 3.8s with a single user call and no manual intervention — confirms the fix works in practice.
There was a problem hiding this comment.
Pull request overview
This PR extends the crow_alarm_panel ESPHome external component with an ISR-level raw bit-trace logging toggle (to aid offline protocol decoding) and improves reliability of the arm/disarm state machine by retrying specific pending states on watchdog timeout (up to 5 times). It also adds extensive trace-based documentation capturing observed failure signatures and supporting the retry rationale.
Changes:
- Add a
log_raw_bitsswitch to enable ISR-side raw DAT-bit batching and INFO-level logging. - Update the arm/disarm watchdog to retry
CODE_DIGIT_PENDING/CODE_ENTER_PENDING/ARM_AWAY_PENDING/ARM_STAY_PENDINGon timeout instead of immediately aborting. - Add/extend protocol trace documentation and state-machine notes with new multi-session findings.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| crow_alarm_panel_test.yaml | Adds a fixture switch entry to toggle raw bit-trace logging. |
| components/crow_alarm_panel/switch/crow_alarm_panel_switch.h | Declares a new switch type for raw bit-trace logging. |
| components/crow_alarm_panel/switch/crow_alarm_panel_switch.cpp | Implements the raw bit-trace switch behavior via parent toggling. |
| components/crow_alarm_panel/switch/init.py | Wires a new log_raw_bits typed switch into schema/codegen. |
| components/crow_alarm_panel/docs/protocol_trace_2026-08-05_disarm_after_arm.md | Adds new trace analysis documenting failure modes and decode methodology. |
| components/crow_alarm_panel/docs/arm_disarm_state_machine.md | Appends findings and documents the new retry behavior and rationale. |
| components/crow_alarm_panel/crow_alarm_panel.h | Adds bit-trace buffering state and ARM/DISARM retry constants/counter. |
| components/crow_alarm_panel/crow_alarm_panel.cpp | Implements ISR bit-trace capture/logging and watchdog retry logic. |
Comparing corrupted frames against Home Assistant's own log timestamps confirmed day/month/year are exactly doubled by a single inserted bit, and that it originates on the panel's transmit side (minutes_hi/lo, sent before the insertion point, always match real time exactly). Halving now recovers the frame instead of discarding it, but only when the recovered date's weekday also matches the frame's own untouched day_of_week field, avoiding the coincidental-valid-value risk already noted in protocol_investigations.md.
- Refresh arm_disarm_state_enter_ms_ before keypress() in the retry block, not after: keypress()->send_packet() can yield and re-enter loop(), so the watchdog could otherwise fire again on the stale timestamp and send extra keypresses (same fix already applied to the output-select retry). - Gate the ISR's bit-trace buffer swap on !bit_trace_ready_ so it can't overwrite bit_trace_buffer2_ while loop() (other core) is still copying it out. - Mark bit_trace_enabled_ volatile, matching ack_pending_/ is_transmitting_. - Reset bit_trace_len_/bit_trace_ready_ on every toggle so disabling mid-buffer and re-enabling can't mix stale bits into a trace chunk.
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.
Summary
CODE_DIGIT_PENDING/CODE_ENTER_PENDING/ARM_AWAY_PENDING/ARM_STAY_PENDINGsequences on timeout (up to 5x) instead of aborting immediately. Six traced sessions established that a timeout in these states reliably means the panel's state never changed, so a blind retry is safe (unlike output-select/zone-bypass, which don't retry). Validated on real hardware (logs-27): a disarm that previously would have silently failed and required the user to notice and retry resolved automatically in 3.8s.CURRENT_TIMEbit-corruption glitch instead of just discarding it. Comparing corrupted frames against Home Assistant's own log timestamps confirmedday/month/yearare exactly doubled by a single inserted bit, and that it originates on the panel's transmit side, not our ISR sampling (the untouchedminutes_hi/minutes_lofield always matches real time exactly). Halving now recovers the frame, but only when the recovered date's weekday also matches the frame's own untouchedday_of_weekfield — avoiding the coincidental-valid-value risk already flagged inprotocol_investigations.md.docs/protocol_trace_2026-08-05_disarm_after_arm.mdand appended todocs/arm_disarm_state_machine.md/docs/protocol_investigations.md, covering the failure signatures (bus collisions, genuine silence, RX decode corruption on either the interface or the passive monitor, and the time-glitch recovery validation) that led to these fixes.Test plan
uv run esphome compile crow_alarm_panel_test.yamlpassesESP_LOGIrecovery line fire🤖 Generated with Claude Code