Skip to content

Let a /set callback refuse a value #102

Open

Description

@dcj

A settable property's set_callback cannot tell the SDK it refused a value. Property._settable_callback() uses the callback's return value only to detect a coroutine and schedule it on async_loop (homie.py:1604-1610); for an async callback, the done-callback inspects only the exception (homie.py:1614-1625). The SDK's own refusal, a payload invalid for the datatype, is logged as reason=propertySetRejected (homie.py:1587-1591); an application refusal (out of range for the hardware's current mode, interlocked, busy) is invisible to the SDK.

The C++ core used by esp32-sdk has this: settable callbacks return bool, true when the value was accepted and false when refused (cpp-sdk homie_settable.h:15-17, esp32-sdk NodeEntity.h:43-44). A refused value is restored, nothing is published, and the refusal is logged (cpp-sdk homie_settable.cpp:217-224).

A plain False return cannot be the signal in Python. The documented set_callback is partial(model.set_entity, capability, prop_id) (building-a-proxy.md:219), and set_entity returns the value it was given (property.py:180-196), so /set false on a boolean property already returns False.

Proposal

  • A callback (sync, or the awaited coroutine) refuses a value by raising a dedicated ebus_sdk.SetRefused. The SDK logs reason=propertySetRefused,propertyID=... at info level, distinct from propertySetCallbackException.
  • Property.set_entity() re-raises SetRefused from its entity_setter; today it logs and swallows every exception (property.py:190-193).
  • Return values keep their current meaning, so existing callbacks are unaffected.
  • Document the contract on set_callback and in doc/building-a-proxy.md.

Convention

The convention ties $target to acceptance: the exact value goes to $target for a target "received (and accepted)" (convention.md:470), a controller "can only assume that the command it sent to the set topic was received and accepted" (:474), and controllers retry "until the value set is being accepted" (:475).

Related: #91. supports_target=True has been inert since 0.25.0 (#95) because the $target stub ran before the payload was accepted; this refusal is the decision point a future $target publish follows.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T32pvgqCzp1qCz7K5gS9Wm

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions