Skip to content

Fix the issues found in the review of 1.0.2 - #8

Merged
DAB-LABS merged 1 commit into
masterfrom
fixes-1.0.3
Sep 6, 2026
Merged

Fix the issues found in the review of 1.0.2#8
DAB-LABS merged 1 commit into
masterfrom
fixes-1.0.3

Conversation

@DAB-LABS

@DAB-LABS DAB-LABS commented Sep 6, 2026

Copy link
Copy Markdown
Owner

I had 1.0.2 reviewed the same way as the last two. Nothing in how the library talks to devices changed, and the review confirmed that again.

It did find an issue when a device's session key expires and the device has since been locked in the app, the library tried to log in again, failed, and raised the login failure instead of the error the device gave the original request. The original library never tried to log in again, so a program written against it, including Home Assistant, handles the first error and may have never seen the second. That is fixed, along with some smaller items.

Tested on Python 3.13 and 3.14, 261 tests, plus a live run against an RM4 Pro.

Coding assistant's notes on this change:

When re-authentication after an expired-key answer fails, the request's own reply is now returned, so the caller sees the same AuthorizationError or ConnectionClosedError the original library raised. The failure is logged at debug level. The README now states this contract and its worst case: one call can wait out up to three timeouts (the request, the authentication, and the repeat).

Also in this change: the authentication generation is read under the request lock, so a request queued behind auth() cannot skip a re-authentication it needs; aclose() racing an endpoint that is still opening no longer leaks the new socket; a new capture window re-checks for a rival claimant after giving the finalizer its turn; CapturedSignal.pulses and ParsedPacket.pulses are tuples, so the frozen dataclasses are hashable; check_error unpacks the error code as little-endian explicitly; the locks are created in init; send_packet accepts bytearray; setup() goes through a public send_setup_packet() helper; the CLI closes its device; and the README adds the A2 and the Hysen HY02/HY03 to the device list. A typing pass (py.typed, mypy in CI) is left for 1.1.

A third review, this one of 1.0.2, found one behaviour that was worse than
the original library's and a handful of small things. Nothing in the wire
format changed. This fixes them. Tested on 3.13 and 3.14, 261 tests,
oracle fixtures unchanged, and live against an RM4 Pro under -X dev.

Technical details:
- When re-authentication after an expired-key answer fails (a device
  locked in the app, say), the request's own reply is returned, so the
  caller sees the same AuthorizationError or ConnectionClosedError the
  original library raised, not an AuthenticationError from the retry. The
  failure is logged at debug.
- The auth generation is read under the request lock, so a request queued
  behind auth() cannot observe a stale one and skip a needed re-auth.
- aclose() racing an endpoint open no longer leaks the new socket; the
  open notices the close and raises EndpointClosedError.
- A new capture window re-checks for a rival claimant after giving the
  finalizer its turn.
- CapturedSignal.pulses and ParsedPacket.pulses are tuples, so the frozen
  dataclasses are hashable.
- check_error unpacks with "<h"; the locks are created in __init__;
  send_packet accepts bytearray; setup() goes through a public
  send_setup_packet() helper; the CLI closes its device.
- README: re-auth contract and worst case (three timeouts), A2 and Hysen
  HY02/HY03 in the device list, hello response mac is bytes.
- Version 1.0.3.
@DAB-LABS
DAB-LABS merged commit 396a1a9 into master Sep 6, 2026
3 checks passed
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.

1 participant