Repository navigation
Conversation
A callback that fails answers -70402 (service communication failure), whatever went wrong: a busy device, a refused request and a broken one look the same to the controller. This is the error protocol of the callback interface refactor (refactor.md); issue #75 asked for it. HapStatusError carries a HAP status the controller receives for the characteristic, e.g. RESOURCE_BUSY for a lock whose motor is moving. The status set is curated: privileges, permissions and timeouts belong to the accessory driver and cannot be raised, a reserved or unknown status fails at construction with a ValueError.
|
|
||
| __slots__ = ("_client_addr", "_generation") | ||
|
|
||
| def __init__(self, client_addr: tuple[str, int] | None, generation: int) -> None: |
There was a problem hiding this comment.
Documented in the constructor docstring now: None only for a call without a connection — a programmatic write/read through the legacy facade, e.g. tests calling client_update_value directly. A controller's request always has an address.
| @property | ||
| def generation(self) -> int: | ||
| """What distinguishes a connection from a reused address.""" | ||
| return self._generation |
There was a problem hiding this comment.
Does that really need to be exposed? The key is what makes a handle unique and this is just an implementation detail IMO.
There was a problem hiding this comment.
Agreed — dropped the public generation property. It stays a driver-assigned constructor parameter, documented as internal; equality and hashing still use it. The handle's interface is now just client_addr.
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class Context: |
There was a problem hiding this comment.
The name is somewhat generic. Perhaps CharContext? CharReadContext and CharWriteContext respectively.
There was a problem hiding this comment.
Renamed to CharContext / CharReadContext / CharWriteContext across the modules, tests and docs. The prefix also keeps room for the lifecycle contexts later, which are not char-shaped.
|
|
||
| ## [Unreleased] | ||
|
|
||
| ### Added |
There was a problem hiding this comment.
Drop the changes to the changelog for now since the design is still in a very early draft.
The API side of the callback interface refactor, ahead of the write and read pipelines that dispatch it: - CharacteristicDelegate and ServiceDelegate: the noop-base interfaces replacing the legacy setter/getter attributes over time. Every method is a coroutine function by design - the driver awaits every call, there is no sync/async detection on this path - and a delegate instance may serve many characteristics: the context carries which one a call is about. - Context, ReadContext and WriteContext: frozen dataclasses carrying what a callback knows about the request - the client's address and identity, the connection handle and the deadline - so new input data arrives as new context fields instead of new callback signatures. - HAPConnectionHandle: the stable identity of a controller connection, equal only for the same connection, never for a later one reusing its address. Camera session ownership adopts it first; the driver's remaining per-client state migrates in a second phase, documented in the class docstring. The driver does not dispatch these yet; they are pure API with unit tests and autodoc pages. HapStatusError from the previous commit rides along as the error protocol of the same interface.
f902694 to
09c4c3a
Compare
|
Closing per maintainer decision — continuing locally; the work continues on local branches and will return as PRs when the design settles. |
The callback interface refactor — the APIs
This PR lays the foundation of the setter/getter callback interface refactor: the pure API — classes, contexts and the error protocol — without any integration into the driver's pipelines yet. The two PRs stacked on top make the first pieces of the driver use it.
The bigger picture
The current callback contract grew ad hoc and shows the strain:
sender_client_addr, detected by literal parameter name).-70402./accessoriesresponse.(ip, port)tuple, which is only unique while a connection lives — several recent fixes (Keep the Setup Endpoints answer per connection #544, Drop the write response of a setter that answers after its connection closed #557) patch instances of that bug class.The redesign, agreed in discussion:
CharacteristicDelegate(on_get / on_set / on_subscribe / on_unsubscribe) andServiceDelegate(grouped on_set), noop-base classes; one instance may serve many characteristics.CharContext/CharReadContext/CharWriteContext):client_addr,client_uuid,connection,deadline,is_admin. New input data arrives as new fields, never as signature changes.TypeError); the driver awaits every call under the context's deadline. No sync/async inference anywhere.HapStatusError: callbacks answer a curated HAP status instead of the generic-70402(closes Allow characteristics to indicate set value failure #75). Reserved codes fail at construction.on_setruns before per-characteristic ones and may veto viaHapStatusError— values restored, nobody notified, nothing applied.client_connected,client_verified, keepclient_disconnected) as overridable Accessory methods.setter_callback/getter_callbackbecome properties wrapping old callables; the legacy pipeline keeps today's semantics byte-for-byte. Existing integrators change nothing until they choose to.This PR: API only
pyhap.errorsHapStatusErrorwith the curated status setpyhap.connectionHAPConnectionHandle— equal only for the same connection, never for a reused address; phased internal migration documented in the docstringpyhap.contextCharContext/CharReadContext/CharWriteContext, frozen dataclassespyhap.delegatesCharacteristicDelegate/ServiceDelegate, noop async basesThe driver does not dispatch any of this yet. Unit tests cover construction, equality/hash, frozenness, coroutine-function defaults and overrides; autodoc pages added under
docs/source/api/. The handle exposes onlyclient_addr— what makes it unique (the address plus an internal generation) is an implementation detail. CHANGELOG entries come with the finished design.Stack: #560 (write path answers
HapStatusError) → #561 (read path + per-characteristic isolation + thebusy_lockexample).