chore(ctw3): add diagnostics to pinpoint detect_status offset (Refs #65)#68
Merged
chore(ctw3): add diagnostics to pinpoint detect_status offset (Refs #65)#68
Conversation
Issue #65: drink-events sensor never increments because the parser reads detect_status from CMD 210 byte 19, which appears to always be 0 on CTW3 firmware 111. The ground-truth log captured by the user (cat Milka drinking; HA UX showed 'detected' then back to 'clear') contains a single post-drink frame whose byte 26 jumps to 0xc5 vs 0x08 in idle frames — strongly suggesting the real detect signal lives in the currently-unparsed bytes 26..29. To gather conclusive evidence without risking a regression on W4/W5/CTW2, this commit ships diagnostic instrumentation only: * New raw_state and state_tail fields on PetkitFountainData populated by both CTW3 and generic CMD 210 parsers. * Coordinator logs a DEBUG-level byte-by-byte diff between consecutive CMD 210 polls, skipping the always-changing uptime tick at bytes 9..18 so semantically meaningful changes (e.g. pet-detection events) stand out. * New hidden DIAGNOSTIC sensor sensor.<device>_state_tail_hex exposes bytes 26..29 of CTW3 30-byte frames so users can graph their behaviour in HA history without grepping logs. Refs #65 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds CTW3-focused diagnostics to help pinpoint the correct detect_status byte offset by preserving/logging raw CMD 210 state payload changes and exposing the unparsed CTW3 tail bytes as a hidden diagnostic sensor.
Changes:
- Capture
raw_state(all models) and CTW3state_tail(bytes 26–29 when present) inPetkitFountainData. - Add a DEBUG-only coordinator log that diffs consecutive CMD 210 payloads while suppressing noisy indices 9–18.
- Add a hidden diagnostic sensor for the CTW3 state tail hex string, plus unit tests for the diff helper and tail parsing.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
custom_components/petkit_ble/ble_client.py |
Persist raw CMD 210 payloads and CTW3 tail bytes into the data model during parsing. |
custom_components/petkit_ble/coordinator.py |
Add byte-diff helper + DEBUG log of changed CMD 210 bytes between polls. |
custom_components/petkit_ble/sensor.py |
Add a hidden diagnostic sensor exposing CTW3 state_tail as hex. |
custom_components/petkit_ble/translations/en.json |
Add entity translation for the new state_tail_hex sensor. |
custom_components/petkit_ble/translations/nl.json |
Add entity translation for the new state_tail_hex sensor. |
custom_components/petkit_ble/translations/uk.json |
Add entity translation for the new state_tail_hex sensor. |
custom_components/petkit_ble/manifest.json |
Bump integration version to 1.1.13. |
tests/test_state_diff.py |
New tests for the CMD 210 byte-diff diagnostic helper. |
tests/test_data_model.py |
Tests covering raw_state + state_tail capture for CTW3 and non-CTW3 parsers. |
…de CTW3 Address Copilot review comments on PR #68: * _diff_state_bytes now reports appended/truncated bytes against 0x00 for both growing and shrinking payloads, matching the behaviour the docstring promised. Two new unit tests pin the contract. * Coordinator only applies the CTW3 uptime-noise filter (bytes 9..18) for CTW3 devices. On 12-byte W4/W5/CTW2 payloads those indices carry pump_runtime tail / filter_percent / running_status, so suppressing them would have made the diagnostic misleading. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 1, 2026
aavdberg
added a commit
that referenced
this pull request
May 1, 2026
…#65) (#69) * fix(ctw3): normalize detect_status so counter sees 0->1 edge (Closes #65) CTW3 firmware 111 emits `0x02` on byte 19 of the CMD 210 state payload when the proximity sensor detects a pet, not `0x01` as previously assumed. The parser stored the raw byte unchanged, so: - `binary_sensor.pet_drinks` (uses `bool(detect_status)`) toggled correctly — value `2` is truthy. - `sensor.drink_events_today` requires a strict `0 -> 1` edge in the coordinator and therefore never incremented. Captured ground-truth (Logs/home-assistant_petkit_ble_2026-05-01T12-01-29.952Z.log): 13:59:13 byte[19]=0x00->0x02 <- cat starts drinking 14:00:23 byte[19]=0x02->0x00 <- cat leaves Fix is one line in `_parse_state_ctw3`: normalise any non-zero byte 19 to `1`. Future-proofs the field against further bit patterns (0x03/0x04 etc.). Tests: - New parser test exercising the captured detect=2 frame. - New parser test for the cleared (byte19=0x00) frame. - New end-to-end test feeding three CTW3 30-byte payloads through parser + `_track_drink_event_into` and asserting the count goes from 0 to 1. Diagnostics shipped in #68 (state_tail_hex sensor + byte-diff log) are left in place as a reusable debugging aid for future offset investigations. Refs #65, follows up #68. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(ctw3): use a real pre-detection idle frame in counter regression test Replaces the synthesised IDLE_BEFORE (detected frame with byte 19 zeroed) with the actual frame captured at 13:58:00 in the ground-truth log, so the test faithfully matches the PR description's claim of three real frames. Addresses Copilot review on PR #69. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Refs #65.
Why
The drink-events sensor never increments. Our CMD 210 parser reads
detect_statusfrom byte 19 of the CTW3 30-byte payload, but in every captured frame across four debug logs (15+ samples) byte 19 is always0x00— including the ground-truth log captured by @aavdberg where his cat was actually drinking and HA UX showedPet drinks = detectedfor a few seconds before flipping back toclear.Looking at the trailing four bytes (26..29) of the CTW3 30-byte frame — currently not parsed at all — there is a strong outlier in the post-drink frame:
08 07 23 0708 07 07 0708 07 ff 0608 07 1f 0719 07 37 07c5 06 be 06Byte 26 is a strong candidate, but a single sample is not enough to risk patching the parser — the same code path runs on W4/W5/CTW2, and an incorrect offset would silently break those devices.
What this PR does (instrumentation only)
raw_stateandstate_tailfields toPetkitFountainData(populated by both CTW3 and generic parsers).sensor.<device>_state_tail_hexexposing bytes 26..29 of CTW3 30-byte frames so users can graph their behaviour in HA history without grepping logs.No parser-offset change yet — we ship the diagnostics first, ask for a fresh log captured with debug enabled before the next observed drink event, and patch in a follow-up PR once the responsible byte is unambiguous.
How to validate (for the user once a pre-release is published)
custom_components.petkit_blein HA configuration.detected, attach to issue CTW3: 'Drink events today' counter never increments #65.Test plan
ruff checkandruff format --check— clean.pytest tests/— 89 passed (4 new tests forstate_tailparsing and the diff helper, including a regression test using the real captured frames).