Skip to content

feat(crow_alarm_panel): decode RF remote events (0x7C), protocol doc updates - #16

Merged
dan-s-github merged 14 commits into
mainfrom
dan-dev
Sep 15, 2026
Merged

dan-s-github merged 14 commits into
mainfrom
dan-dev

Conversation

@dan-s-github

@dan-s-github dan-s-github commented Sep 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Decode 0x7C as an RF remote button-press event (per-remote identity + per-button code, logged rather than acted on) and document its byte layout, causality, and vendor-manual cross-reference in docs/protocol_wire_format.md.
  • Add docs/known_quirks.md: a user-facing translation of the reverse-engineering docs — recurring log WARNs and behaviors (retry sequences, corruption bursts, etc.) a user could actually notice, why they happen, and whether action is needed. Linked from README.md and CLAUDE.md.
  • Extend docs/protocol_investigations.md and docs/arm_disarm_state_machine.md with several trace-derived findings from the ongoing long-term capture: RF remote decode, CURRENT_TIME ×4 corruption-multiplier root cause, an output-select sequence recovering cleanly from mid-sequence bus corruption, and an ARMED_STATE malformed-decode revision.

Test plan

  • uv run esphome config crow_alarm_panel_test.yaml (config validation)
  • uv run esphome compile crow_alarm_panel_test.yaml (compile check)

dan-s-github and others added 10 commits September 7, 2026 17:20
Frigate window 2026-09-05 20:47 -> 2026-09-07 05:14 UTC: every clustered
ff./fe. burst still precedes a watchdog trip (5/5 across two windows), one
burst now cost two consecutive trips. Bigger finding: an 8h36m-armed disarm
retried with CURRENT_TIME confirmed normal throughout, mirroring the
existing confirmed-stuck-but-instant case -- the CURRENT_TIME-stuck/retry
correlation tracked since 2026-08-31 no longer looks predictive either way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lf3cEpQ9z4E8bEeb95ovEy
Manual bit-level decode of the raw bit trace around the 2026-09-07 watchdog
bursts shows the same two corrupted frames repeating each time, matching the
already-documented controller-retransmission-storm mechanism, with the
isolated single fe. line landing on a different keypad's slot as expected.
A stateful ISR replica didn't reproduce the real logged counts, tracing to
a previously undocumented limitation: the bit-trace buffer itself silently
drops bits under load, unlike the (already-fixed) frame queue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lf3cEpQ9z4E8bEeb95ovEy
Frigate capture review for 2026-09-07 05:14 -> 2026-09-08 08:40 UTC.
Poll-slot/watchdog correlation extends to 7/7 with no exceptions; the
invalid-minutes-since-midnight fault recurred a 3rd day running at the
same 11:25:55-11:27:40 UTC window, and the day/month=*/36 fault gained
a new day value (32) extending the fixed +4 set.
Give the RF remote's button-press frame (data[0..2] remote identity,
data[3..4] button code) a proper log line instead of falling through
to the generic Unknown handler.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsSRQuhQShyCnUNPsfqaQ
Two-remote scripted button test decodes all four RF remote functions
(arm/disarm/gate/garage) against OUTPUT_STATE and confirms 0x7C
causality precedes the controller's action by ~100-150ms.

Cross-references the vendor ESL-2 install/programming manual: confirms
the RF-remote (0x7C) attribution and per-button radio-user addressing,
and resolves the Output-1 siren-chirp mechanism as the documented
Pendant Arm/Disarm Chirp feature (P50E-P53E).

Resolves the long-open "invalid day/month value */36" mystery from the
frigate log-mining effort: it's real_calendar_value x 4, caught live
transitioning across a local-midnight rollover, not a stuck or
independently-incrementing value.

Proposes then disproves a dialler-test-call hypothesis for the daily
invalid-minutes-since-midnight glitch (wrong configured time, and the
dialler isn't active on this installation) -- recorded so the
explanation isn't re-proposed later.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsSRQuhQShyCnUNPsfqaQ
Frigate long-term log window 2026-09-10 04:55 -> 2026-09-13 04:14 UTC:
first observed case of ff./fe. bus corruption disrupting an in-flight
Output-select sequence (timeout/retry + recovery both fired, sequence
still completed correctly), documented alongside a new known_quirks.md
entry mirroring the existing arm/disarm-retry one. Also revises the
malformed 7-byte ARMED_STATE decode from "disarm-after-arm-specific" to
"rare receiver-side glitch" after a second occurrence with no adjacent
arm/disarm activity.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqNbZBEyPpzMhXAB5wk2Y6
Frigate long-term log window 2026-09-13 04:14 -> 2026-09-14 07:26 UTC:
ff./fe. corruption and watchdog trips both zero for the full ~27h span,
and the one integration disarm retry this window (9h31m armed, normal
CURRENT_TIME) had no bus corruption anywhere nearby -- the cleanest
counter-example yet against the corruption-proximity retry theory.
Also logs a 3rd malformed ARMED_STATE decode with a new type-byte variant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014n8DhRT3HAsqKrNkb11ETi

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The RF parser accepts truncated frames as valid button events, and documentation corrections remain outstanding.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds passive, log-only decoding for RF remote 0x7C events and expands protocol documentation with trace findings and user-facing quirks.

Changes:

  • Adds RF event recognition, identity, and button logging.
  • Documents packet layouts, causality, corruption, retries, and state-machine findings.
  • Adds and links a known-quirks guide.
File summaries
File Summary Review notes
components/crow_alarm_panel/README.md Links the known-quirks guide. No findings.
components/crow_alarm_panel/docs/protocol_wire_format.md Documents RF packet details and causality. Nits: correct the receiver-to-controller direction and qualify timing measurements, including the same-millisecond exception.
components/crow_alarm_panel/docs/protocol_investigations.md Adds trace-derived protocol findings. Nits: correct the event count and qualify the observed timing range.
components/crow_alarm_panel/docs/known_quirks.md Adds user-facing troubleshooting guidance. Nits: correct log-level wording, stale watchdog/corruption conclusions, grammar, and CURRENT_TIME recovery behavior.
components/crow_alarm_panel/docs/arm_disarm_state_machine.md Updates retry investigation history. No findings.
components/crow_alarm_panel/crow_alarm_panel.h Defines the RF event constant. No findings.
components/crow_alarm_panel/crow_alarm_panel.cpp Decodes and logs RF remote events. Moderate: truncated 3–7 byte frames can be logged as valid button events instead of being rejected.
CLAUDE.md Documents known-quirks maintenance guidance. No findings.
Review details

Suppressed comments (6)

components/crow_alarm_panel/docs/known_quirks.md:31

  • This summary is stale relative to the new 2026-09-14 investigation entry: a retry occurred during a full 27-hour window with zero ff./fe. corruption or watchdog activity, so corruption/watchdog proximity is explicitly no longer the current lead. Describing it as the current lead will send users toward a hypothesis the updated evidence has undermined; update this sentence to reflect that the cause remains open and lower priority.
cause has been confirmed — a `CURRENT_TIME` correlation theory was tested and later ruled
out; a bus-corruption/watchdog-proximity theory is the current (unconfirmed, single-data-point)
lead. See `arm_disarm_state_machine.md` for the full retry investigation history.

components/crow_alarm_panel/docs/known_quirks.md:86

  • Use the article an before the Unknown log label.
exactly when a `Unknown [ff.]`/`[fe.]` corruption burst (see above) happens to land in

components/crow_alarm_panel/docs/known_quirks.md:111

  • The implementation can recover the known doubled-date corruption when its weekday check succeeds (crow_alarm_panel.cpp:604-618); it only discards unrecoverable values. Saying all corrupted CURRENT_TIME frames are discarded is inaccurate and contradicts that recovery behavior. Please describe the validation/recovery path instead.
**What to do:** nothing — the component already discards corrupted `CURRENT_TIME` frames
rather than acting on them, and no entity depends on this data.

components/crow_alarm_panel/docs/protocol_investigations.md:865

  • The conclusion here also generalizes the timing as roughly 100 ms for all eight combinations, but the table immediately above has one same-log-millisecond case and measured deltas from +98 to +147 ms. Keep the causal ordering claim, but qualify the delay to match the observed values and timestamp resolution.
**Inference (high confidence):** this directly answers the open question from the 2026-09-09 second-follow-up entry above ("not yet established whether `0x7C` and the siren chirp are cause-and-effect... or two independent effects") — `0x7C` is upstream: the RF receiver hardware reports the button press to the controller, which then acts on it and broadcasts the state change roughly 100ms later. Not a parallel/simultaneous echo of an action already decided elsewhere. Written into `protocol_wire_format.md`'s `0x7C` entry as a new "Causality" paragraph.

components/crow_alarm_panel/docs/protocol_wire_format.md:494

  • This timing summary overstates the uniformity of the measurements: the detailed table reports deltas from +98 to +147 ms, while Remote A's arm case is only "same log ms, 0x7C logged first." Please describe the measured range and the same-millisecond/log-order exception instead of saying all eight were ~100–150 ms.
**Causality (high confidence, resolves the previously-open question):** the first `0x7C` frame of each pair precedes the controller's resulting action (the `ARMED_STATE`/`Disarmed` broadcast, or the `OUTPUT_STATE` pulse) by ~100–150ms in all 8 button presses checked (both remotes × all 4 buttons) — never simultaneous-or-after. `0x7C` is therefore the RF receiver reporting the button press *to* the controller, which then acts on it ~100ms later — a cause, not a parallel echo of an action already taken.

components/crow_alarm_panel/docs/protocol_wire_format.md:451

  • The new causality section identifies the RF receiver as reporting the button press to the controller, but this field still says Unknown source → broadcast. That is contradictory and leaves protocol implementors with the wrong direction; update it to the confirmed receiver-to-controller direction or explain why the direction remains unknown.
*Direction:* Unknown source → broadcast (not yet attributable to a keypad address; no `keypad_addr` byte pattern matches the existing keypad-address convention)  
  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread components/crow_alarm_panel/crow_alarm_panel.cpp Outdated
Comment thread components/crow_alarm_panel/docs/known_quirks.md Outdated
Comment thread components/crow_alarm_panel/docs/known_quirks.md Outdated
Comment thread components/crow_alarm_panel/docs/protocol_investigations.md Outdated
Reject RF remote frames shorter than 5 bytes (need data[3..4] for the
button code) instead of the too-loose 3-byte minimum, which let
truncated frames log as valid button events. Also fixes several doc
inaccuracies the review caught: a stale "Unknown source" direction note
contradicting the new causality finding, an overgeneralized ~100ms
timing claim, a wrong button-count sum, and known_quirks.md claims that
had gone stale relative to the 2026-09-14 zero-corruption retry
counter-example and the CURRENT_TIME recovery logic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The RF payload-length guard and several documentation details remain inconsistent with the documented behavior.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (7)

components/crow_alarm_panel/crow_alarm_panel.cpp:926

  • This log labels the packet type (type, always 0x7c) as the button event, while the per-button code is data[3..4]. As written, every button log has the same button label and the new decode does not expose which button code was received; log data[3] and data[4] explicitly.
        ESP_LOGD(TAG, "[RF Remote %02x:%02x:%02x] Button event [%02x.%s]", data[0], data[1], data[2], type,
                 format_hex_pretty(data).c_str());

components/crow_alarm_panel/docs/arm_disarm_state_machine.md:605

  • This says the bus cannot distinguish RF-remote input, but this PR adds exactly that distinction: the preceding 0x7C frame is now decoded and logged before the ARMED_STATE broadcast. Please scope the limitation to ARMED_STATE/keypress context alone so this historical comparison does not contradict the new protocol finding.
**Source:** the frigate long-term logger, window 2026-09-08 08:40 → 2026-09-09 05:09 UTC. Three arm/disarm sequences this window; the first two were confirmed by the user to be triggered by the official RF remote (distinct chime pattern: once on arm, twice on disarm) rather than a keypad or this integration — the bus itself can't distinguish remote-fob input from any other non-integration source, since both simply appear as Controller `ARMED_STATE` broadcasts with no accompanying keypress/command traffic.

components/crow_alarm_panel/docs/arm_disarm_state_machine.md:641

  • This repeats the now-stale claim that the bus cannot identify a remote-fob event. With the new 0x7C decoder, the bus trace has a direct RF-remote signature; only an ARMED_STATE broadcast considered in isolation is ambiguous. Please update this note to reflect that distinction.
- Audible chime count on the official RF remote distinguishes it from other input sources when reading a trace: **one chime on arm, two chimes on disarm** (confirmed by the user, 2026-09-09). Useful because the bus itself can't tell remote-fob input apart from any other non-integration source — both simply appear as a Controller `ARMED_STATE` broadcast with no accompanying keypress/command traffic, unlike physical-keypad or integration-initiated sequences which leave a `Code sequence:`/keypress trail

components/crow_alarm_panel/docs/protocol_investigations.md:905

  • The default 240-minute interval is exactly 6 × 240 = 1440 minutes, so it does divide evenly into a day. This incorrect arithmetic dismisses a potentially relevant periodic source; please correct the statement while keeping the phase/configuration uncertainty explicit.
**Follow-up (2026-09-10, same day): hypothesis disproven, and doubly so.** User checked `P175E4E` directly on the physical LCD keypad — the panel's configured Test Call Start Time is `02:00` (NZST), not anywhere near `23:25`–`23:28`. On top of that, the user believes the dialler itself (`P175E1E` Option 1, "Dialler is Enabled") is not active at all — no monitoring service/phone line in use on this installation — so even the `02:00` value is a vestigial default that never actually fires a call. This rules out the Automatic Test Call as the trigger for the daily `invalid minutes-since-midnight` episode on two independent grounds (wrong time, *and* the feature isn't even running). `02:00` NZST = `14:00` UTC doesn't line up with any other currently-documented daily-timed signature either (checked against this file and `arm_disarm_state_machine.md` — no match). The "what happens near `11:26` UTC daily" question reverts to fully unidentified, with the dialler-contention mechanism ruled out specifically — worth remembering not to re-propose that particular explanation, including any dialler-related mechanism generally (test calls, DTMF, modem tones), since the dialler isn't believed to be active on this panel at all. If a future session wants another candidate, look elsewhere in the panel's periodic/scheduled behaviors (e.g. the radio-detector supervised-timer check-in cycle, `P25E4E`, default 240 min — doesn't divide evenly into a once-daily period at the default, but worth a look if it's been reconfigured).

components/crow_alarm_panel/docs/protocol_investigations.md:853

  • The source test reports 16 physical presses (8 per remote), while this heading and the next line say "all 8 presses." The table contains 8 remote/button combinations, so distinguish combinations from physical presses and state whether the ordering check covered one representative press per combination or all 16.
### Update (2026-09-10, cont.): `0x7C` precedes the controller's action by ~100–150ms in all 8 button presses — resolves the cause-vs-parallel-effect question left open on 2026-09-09

**Source:** user asked directly whether the `0x7C` frames arrive before the action they correlate with; checked sub-millisecond ordering for all 8 presses from the update above.

components/crow_alarm_panel/docs/protocol_wire_format.md:453

  • This section says an RF event requires 8 payload bytes, but the handler accepts and logs any 5-byte payload because the first five bytes are the identity plus per-button code it decodes. Please distinguish the parser's minimum from the 8-byte shape observed in captures; otherwise the documentation and implementation disagree about which short frames are valid.
*Min length:* 8 payload bytes  

components/crow_alarm_panel/docs/protocol_wire_format.md:494

  • The scripted test above reports 16 physical presses (8 per remote), but this sentence calls the causality sample "all 8 button presses." The table appears to cover 8 remote/button combinations, so clarify whether one representative press per combination was checked or all 16 presses; otherwise the evidence sample size is ambiguous.
**Causality (high confidence, resolves the previously-open question):** the first `0x7C` frame of each pair precedes the controller's resulting action (the `ARMED_STATE`/`Disarmed` broadcast, or the `OUTPUT_STATE` pulse) in all 8 button presses checked (both remotes × all 4 buttons) — never simultaneous-or-after. Measured deltas range from +98ms to +147ms, with one exception (Remote A's arm case landed in the same logged millisecond, `0x7C` still ordered first in the log). `0x7C` is therefore the RF receiver reporting the button press *to* the controller, which then acts on it roughly 100ms later — a cause, not a parallel echo of an action already taken.
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Lite

break;
}
case RF_REMOTE_EVENT: {
if (data.size() < 5) {
Log the RF remote's actual button code (data[3..4]) instead of just
the packet type, so distinct buttons no longer produce identical log
lines. Reconcile the wire-format doc's "8 payload bytes" minimum with
the parser's real 5-byte requirement. Fix a 240/1440-minute divisibility
error in the P25E4E speculation. Clarify "8 button presses" as 8
button/remote combinations (one representative press each), not all 16
physical presses. Scope two historical "bus can't distinguish RF-remote
input" notes in arm_disarm_state_machine.md to "ARMED_STATE considered
in isolation," since this PR's 0x7C decode is now a direct signature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Two unresolved documentation inconsistencies remain in the protocol investigation and wire-format references.

Review details

Suppressed comments (2)

components/crow_alarm_panel/docs/protocol_investigations.md:502

  • ARMED_STATE is 0x11, and the C++ switch only emits Armed state unknown inside that case. A frame rendered as [13.83...] has type 0x13 and would instead be logged by the default branch as Unknown [13...], so this new observation is inconsistent with the implementation and with the type-byte-corruption inference below. Please describe it as the malformed/unknown 0x13 frame and adjust the heading accordingly.
### Update (2026-09-14): `ff.`/`fe.` corruption and watchdog trips both drop to zero for a full ~27h window; third `ARMED_STATE` malformed-decode occurrence has a different type byte than the first two

**Source:** frigate long-term logger, window 2026-09-13 04:14 → 2026-09-14 07:26 UTC (~27h13m, no reboot/OTA in-window) ([[project-crow-alarm-protocol-trace]]).

**Findings (observed facts):** zero `Unknown [ff.]`/`[fe.]` lines anywhere in the entire window — a sharper version of the 2026-09-06 dip (2-in-21h) with no corruption at all this time, against an established baseline of ~0.84–0.94/h. Registration-watchdog trips: also zero, consistent with (not a counter-example to) the poll-slot/watchdog mechanism, since there was no corruption burst to trigger one. Frame-FIFO backlog/overflow counters stayed at zero throughout, and no truncated-frame WARNs (`Controller status too short`, `Zone state invalid length`, `Output state too short`, `Current time too short`) occurred. A third instance of the malformed 7-byte `Armed state unknown` decode appeared at `2026-09-13 15:40:25` UTC — `[13.83.01.46.81.00.80.11 (7)]`, identical to the previous two except the leading type byte is `0x13` rather than `0x11` (bytes 2–7 unchanged) — again with no adjacent arm/disarm activity, consistent with the 2026-09-13 revision to "rare receiver-side glitch, not context-gated."

components/crow_alarm_panel/docs/protocol_wire_format.md:435

  • This wording overgeneralizes the observed September case: halving a ×4 month gives 2×month, which is out of the 1–12 range for months 7–12 but remains in range for January–June (with the weekday check then determining recovery). Please scope the claim to the observed month=36/September data or describe the full condition so the protocol reference does not imply every ×4 frame is rejected for this reason.
A related but distinct variant fails this recovery outright: `day`/`month` corrupted by
a `×4` (not `×2`) multiplier, which still halves to an even number but lands `month` out
of the valid `1–12` range, so the frame is discarded rather than silently mis-recovered.
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

The 2026-09-14 malformed-decode entry called a type-0x13 frame an
"Armed state unknown" decode, but ARMED_STATE's switch case only
matches 0x11 — a 0x13 frame actually falls through to the default
branch and logs as "Unknown [13...]". Corrected the heading and body
to describe it accurately.

The CURRENT_TIME x4-corruption note claimed the day/month recovery
logic always rejects x4-corrupted frames via the out-of-range check.
That's only guaranteed for real_month >= 7 (all cases observed so
far); for real_month <= 6 the single-halving recovery lands back in
the valid 1-12 range and only the probabilistic weekday cross-check
would catch it. Documented as a theoretical gap, not yet observed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Documentation claims remain inconsistent with the recorded evidence, including an overstated behavior frequency.

Review details

Suppressed comments (9)

components/crow_alarm_panel/docs/arm_disarm_state_machine.md:641

  • The new summary omits the exception recorded in protocol_wire_format.md: Remote A's arm event had the 0x7C frame ordered first in the same logged millisecond, not 100–150 ms earlier. Qualify this as the typical measured delay so readers do not treat that latency as guaranteed.
- Audible chime count on the official RF remote distinguishes it from other input sources when reading a trace: **one chime on arm, two chimes on disarm** (confirmed by the user, 2026-09-09). This was historically the only way to tell, since an `ARMED_STATE` broadcast considered in isolation looks the same as any other non-integration source — no accompanying keypress/command traffic, unlike physical-keypad or integration-initiated sequences which leave a `Code sequence:`/keypress trail. A direct on-bus signature now also exists: the `0x7C` RF-remote-event frame (see `protocol_wire_format.md`) precedes the resulting `ARMED_STATE` broadcast by ~100–150ms, so a trace no longer has to rely on the chime alone

components/crow_alarm_panel/docs/known_quirks.md:28

  • This summary contradicts the retry history documented in the same PR: the 2026-08-19 entry records two disarm calls exhausting the then-five-retry budget and aborting. Please scope the claim to the post-six-retry-backoff period and update the “has not been observed” sentence below, otherwise users are told a failure has never occurred when it has.
controller doesn't confirm in time. This has always resolved successfully within the
6-retry budget in every case observed so far (worst case seen: ~42s). No root cause has

components/crow_alarm_panel/docs/known_quirks.md:77

  • Unknown [ff.]/[fe.] bursts are not always merely cosmetic: the entries immediately below document that the same burst can trigger this component's watchdog and delay an in-flight output sequence. Limit this statement to isolated lines and describe clustered bursts as self-recovering but potentially disruptive.
**What to do:** nothing — purely cosmetic log noise from bus-level behavior outside this
integration's control.

components/crow_alarm_panel/docs/known_quirks.md:55

  • This attributes arm/disarm retries to the same corruption mechanism, but the linked arm/disarm investigation explicitly says corruption proximity was not established and has clean counterexamples. Keep the confirmed output-select mechanism here, but state that arm/disarm's cause remains open.
**Cause:** the same bus-corruption noise documented below (`Unknown [ff.]`/`Unknown [fe.]`)
can occasionally land in the slot where the controller's next confirmation was expected
during an output-select sequence, same as it can for arm/disarm. The state machine's
built-in timeout/retry and out-of-sequence recovery logic re-synchronizes and completes

components/crow_alarm_panel/docs/known_quirks.md:85

  • The stated frequency is inconsistent with the evidence summarized here: the investigation records full ~21–27-hour windows with zero watchdog trips and rates around 0.05–0.2/hour, not a stable 'every few hours' cadence. Please describe this as intermittent with highly variable frequency rather than setting that expectation.
**What you'll see:** a `WARN`-level log line, roughly every few hours in long-term
captures, followed immediately by the integration re-registering itself on the bus. No
functional interruption — entities keep working normally.

components/crow_alarm_panel/docs/known_quirks.md:117

  • The new ×4 analysis explicitly identifies a theoretical gap: for a ×4-corrupted date in real months 1–6, halving plus the weekday check can accept an in-range but wrong date by chance. This text currently presents the recovery/discard path without that caveat, which overstates its safety.
**What to do:** nothing — for day/month/year the component tries to recover the known
doubled-bit glitch first (cross-checked against the frame's own weekday field before
trusting the recovery) and only discards the frame if that check fails; other invalid
fields are discarded outright. Either way, no entity depends on this data.

components/crow_alarm_panel/docs/protocol_investigations.md:810

  • These new 2026-09-09/10 RF entries are appended after ## Raw bit trace... but are formatted as ### Update, so Markdown renders them as subsections of the raw-trace investigation; the later 2026-09-10 automatic-test-call entry is similarly grouped there despite being a CURRENT_TIME investigation. Please restore topic-level ## headings or place each update under its actual section.
### Update (2026-09-09, follow-up): the two remote-triggered sequences both carry a previously-unseen `Unknown [7c...]` packet pair, exclusively — new unlabeled type documented in `protocol_wire_format.md`

components/crow_alarm_panel/docs/protocol_wire_format.md:436

  • This new ×4 discussion relies on the “single-halving recovery above,” but the preceding text still says corrupted frames should be discarded rather than corrected even though the implementation deliberately recovers the known ×2 date glitch (crow_alarm_panel.cpp:604-618). Please distinguish known, range/weekday-validated recovery from unrecognized corruption so the protocol contract is not contradictory.
A related but distinct variant exists: `day`/`month` corrupted by a `×4` (not `×2`)
multiplier. Confirmed (2026-09-10) as `real_value × 4`, not arbitrary garbage — see
`protocol_investigations.md`'s 2026-09-10 update for the live midnight-crossing capture
that pins this down. Every occurrence observed so far has had `real_month ≥ 7`

components/crow_alarm_panel/docs/protocol_wire_format.md:458

  • Min length is used elsewhere in this document for the parser's minimum accepted payload, and the new parser accepts 5 bytes (data[0..4]), whereas this entry labels 8 observed bytes as the minimum. Please distinguish the parser minimum from the observed full-frame length to avoid misleading future implementations.
*Min length:* every capture observed is 8 payload bytes; the parser only requires 5 (`data[0..2]` identity + `data[3..4]` button code) since those are all it decodes  
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

- known_quirks.md: scope the "always resolved within budget" retry
  claim to post-budget-increase behavior and mention the 2026-08-19
  exhaustion under the old 5-retry budget that motivated the fix;
  stop implying arm/disarm retries share the output-select corruption
  mechanism (that's explicitly unconfirmed, unlike output-select's);
  acknowledge ff./fe. bursts can trigger downstream watchdog/retry
  symptoms rather than calling them purely cosmetic; replace the
  inaccurate "roughly every few hours" watchdog cadence with the
  actual highly-variable observed rates; note the x4 CURRENT_TIME
  recovery-gap caveat.
- arm_disarm_state_machine.md: qualify the 0x7C causality delay as
  typical, not universal (one case was same-millisecond).
- protocol_wire_format.md: stop saying corrupted CURRENT_TIME frames
  are discarded-not-corrected when the implementation deliberately
  recovers the known x2 glitch; reword the 0x7C Min length line to
  match the doc's own "N required (M seen in practice)" convention.
- protocol_investigations.md: add two `##` topic headings so the
  newly-added RF-remote and CURRENT_TIME-periodicity entries stop
  rendering as subsections of the unrelated "Raw bit trace" section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dan-s-github
dan-s-github requested a lite review from Copilot September 15, 2026 08:49
@dan-s-github
dan-s-github merged commit 3a8ab4b into main Sep 15, 2026
1 check passed
@dan-s-github
dan-s-github removed the request for review from Copilot September 15, 2026 09:22
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