Skip to content

vNext: Change bind procedure - #546

Merged
RobHofmann merged 10 commits into
RobHofmann:5.0-devfrom
p-monteiro:different-bind-procedure
Oct 8, 2026
Merged

RobHofmann merged 10 commits into
RobHofmann:5.0-devfrom
p-monteiro:different-bind-procedure

Conversation

@p-monteiro

@p-monteiro p-monteiro commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

This changes 2 things:

  1. Moves the binding state to the transport. This way, for VRF setups, a device that requests a bind (with the controller MAC) can get a previous subunit-binding response, which should be the same, removing the need to bind again with the controller for each subunit. Now, only the first binding to a controller is saved and cached. The state is cleared if no device is subscribed in the transport for that controller MAC. If a sub-unit rebinds, all get the latest data automatically.
  2. Test device responsiveness with the canary prop when communication fails

Because the protocol does not guarantee an alignement of requested properties and returned values, make the first time fetching properties to query a single property at a time to ensure a 1:1 mapping of their values. This is important because the first fetch defines device capabilities
This allows for a single controller to be bound once. In a VRF setup, consecutive subunits reuse the same binding info as the first unit
p-monteiro and others added 7 commits October 7, 2026 12:23
Before, MAX_UNANSWERED_IN_A_ROW with error_as_missing set to True would mean that after MAX_UNANSWERED_IN_A_ROW the remaining props being queried would be marked as missing. However MAX_UNANSWERED_IN_A_ROW should be a error check for when the device stops responding alltogether, meaning a device is not supposed to not respond to a prop for more that MAX_UNANSWERED_IN_A_ROW. If it does, it should be raised as an error and break whatever thing was using query_props.
…ng after MAX_UNANSWERED_IN_A_ROW

Instead of assuming that after MAX_UNANSWERED_IN_A_ROW the device is unresponsive, do a last check with STATUS_CANARY_PROP and continue if device responds to that.
This allows multiple devices sharing the same controlelr to reuse the same binding information and have all devices updated when a single device in the controller updates the binding.
…ommunication instead of relying on MAX_UNANSWERED_IN_A_ROW to signal a failure
Allow batching since this does not seem like a problem. No real/world regists of it failing alignement in fetch status, only in set status.
- DeviceApiClient called add_device and remove_device with the device and
  controller MACs swapped. For a VRF sub-unit, connections was keyed by the
  sub-unit MAC, the listener sat on the gateway MAC, and bound was always
  False, so every poll sent a new bind request (2 sub-units: 5 binds at
  setup, then 1 per poll). The calls now use keyword arguments.
- set_controller_binding_info used setdefault, so a forced rebind kept the
  old key while another sub-unit of the controller was connected. A new
  binding now replaces the old one for every device of the controller.
- The cipher property never returns None, so the two None checks on it were
  dead code. They now check binding_info.
- Small fixes: loop without enumerate, two typos, query_props docstring.

Tests: the MQTT transport tests and FakePushTransport use the new
add_device/remove_device API. The sweep breaker test is replaced by two
canary tests. Four new tests cover the shared bind per controller; all four
fail on the previous commit. FakeGreeDevice gets an ignored_props keyword.

Docs: protocol.md describes the canary and the bind per controller,
architecture.md and actions.md drop MAX_UNANSWERED_IN_A_ROW.
Without error_as_missing the error is raised either way, so the canary only
added up to 2 x PROBE_TIMEOUT and an "Assessing if device is responding"
warning to every poll of a unit that is switched off. A normal poll now
raises at once and marks the device unavailable. The canary stays for
error_as_missing sweeps, where its answer decides between "ignored prop"
and "device gone".

On my test unit, get_prop_values with ElcDatDte and ElcDatHor: both time out
(10 s), the canary is answered in about 15 ms, and the sweep returns Pow,
SetTem and Lig with the two ElcDat props as missing.
Fix VRF binding on the transport, update tests and docs
@p-monteiro
p-monteiro marked this pull request as ready for review October 8, 2026 23:11
@RobHofmann
RobHofmann merged commit 5e18a8e into RobHofmann:5.0-dev Oct 8, 2026
4 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.

2 participants