Repository navigation
Match the real CT on zero-MAC probes and normalize CT_MAC - #728
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdNTZmPUm4RsPv96EUvWYq
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughCT002 now accepts unpaired-battery requests addressed to the all-zero MAC when a CT MAC is configured. AstraMeter normalizes configured MACs and returns the configured MAC in its reply. Cloud reporting now falls back to the running device’s CT MAC. ChangesCT MAC pairing compatibility
Cloud report ID selection
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to
|
95822c3 to
2e81aa4
Compare
Follow-up to #727, checked against decompiled firmware. The CT002/CT003 images (HME-4 v120/v124, HME-3 v116/v117/v118/v122) answer CT MAC 000000000000 as a wildcard next to their own MAC and always reply with their own type and MAC. An empty CT MAC field fails the CT's sscanf and is dropped, so only 000000000000 is a wildcard here too, on both stacks (WILDCARD_CT_MAC). The battery side (VNSE3-0 v151, HMG-50 v156) compares the reply's CT MAC to its bound one with strcmp, so Python now normalizes CT_MAC to lowercase hex without separators, as the ESPHome config validator already does; cloud reporting uses the normalized MAC too. Adds Python tests, a host-binary e2e test for the C++ side (test.host.yaml now binds a ct_mac), docs and a changelog entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdNTZmPUm4RsPv96EUvWYq
2e81aa4 to
a51716c
Compare
Follow-up to #727 (merged).
Why
#727 (@kvanbiesen) fixed a Marstek Venus E Mini (
VNSEM-0) failing to pair with the emulated CT whenCT_MACis set. An unpaired battery probes with CT MAC000000000000, and the emulator used to ignore it. This follow-up brings that fix in line with what the real CT firmware does and closes a related pairing gap.Verified against decompiled firmware (images from rweijnen/marstek-firmware-archive and sphings79/marstek-firmware-archiv):
HME-4v120/v124) and CT003 (HME-3v116/v117/v118/v122):000000000000as a wildcard, as well as its own MAC.sscanf(%13[^|]), so the CT drops it. Answer zero-MAC CT probes with the configured CT MAC (VNSMINI V301) #727 accepts an empty one too.VNSE3-0v151) and Venus E 2.0 (HMG-50v156):000000000000. It accepts any reply and puts the reply's CT MAC into its next requests.strcmps the reply's CT MAC against it, so case and separators must match exactly.VNSEM-0image, so the Mini's own handshake is unverified.Changes on top of #727:
000000000000is a wildcard (WILDCARD_CT_MACin Python and C++); an empty CT MAC is ignored again, as on a real CT.CT_MACnormalization (Python).CT_MACis normalized to lowercase hex with no separators, as the ESPHome validator already does. Before this, aCT_MAClikeAA:BB:CC:DD:EE:FFcould never pair. Cloud reporting uses the normalized MAC too.docs/ct002-ct003-protocol.md, theCT_MAChelp inconfig.ini.exampleanddocs/ct002.md, and the add-on option description are updated.tests/test_ct002_mac_policy.pycovers the wildcard, empty-MAC and normalization cases.test.host.yamlnow binds act_mac. The newtest_ct_mac_policyintest_host_e2e.pychecks the ESPHome host binary over real UDP. I confirmed it fails with the C++ wildcard line removed.test_ct_settings_wiring's string sentinel no longer contains a-, which the normalization would strip.Checklist
develop, notmainuv run ruff format . && uv run ruff check . && uv run mypy src/ && uv run pytest: ruff, ruff format and mypy are clean. Results:tests/components/ct002/, including the host-binary e2e, passes.develop(Answer zero-MAC CT probes with the configured CT MAC (VNSMINI V301) #727 merged).WILDCARD_CT_MACon both sides; ESPHome already normalizedct_mac)web/changes: none, so no bundle rebuild## Nextin CHANGELOG.md, covering Answer zero-MAC CT probes with the configured CT MAC (VNSMINI V301) #727 and this PR🤖 Generated with Claude Code
https://claude.ai/code/session_01GdNTZmPUm4RsPv96EUvWYq
Summary by CodeRabbit