Skip to content

Dispatch STATE_CONNECTED only on auto-reconnect#19

Merged
SteveEasley merged 2 commits intoSteveEasley:mainfrom
robotdan:fix/state-connected-signal-on-reconnect-only
Apr 5, 2026
Merged

Dispatch STATE_CONNECTED only on auto-reconnect#19
SteveEasley merged 2 commits intoSteveEasley:mainfrom
robotdan:fix/state-connected-signal-on-reconnect-only

Conversation

@robotdan
Copy link
Copy Markdown
Contributor

@robotdan robotdan commented Apr 2, 2026

Summary

Connection._connect() dispatches STATE_CONNECTED unconditionally.

Since _connect() is called from both Connection.connect() (initial) and Connection._reconnect() (auto-reconnect), consumers receive the signal in both cases.

During initial connect, this signal is redundant — the caller already knows the connection succeeded because await device.connect() returned without raising. The signal's value is in notifying consumers about asynchronous events they didn't initiate, which only applies to auto-reconnect.

In practice, this forces consumers to distinguish initial connect from reconnect.

For example, the Unfolded Circle kaleidescape integration needs a _connecting guard flag as a workaround because the STATE_CONNECTED handler runs during Device.connect() while device info is still being fetched via asyncio.gather() — causing queries against incomplete state.

Suggested change

There were tests that asserted the prior behavior, so this may have been an intentional design choice. But here is a suggested change.

Move self._dispatcher.send(const.STATE_CONNECTED) from _connect() to the else block of _reconnect(). _connect() still sets self._state = const.STATE_CONNECTED so all state checks (including is_connected) work correctly.

The signal now only fires for asynchronous reconnection events.

Impact on consumers

The Home Assistant kaleidescape integration registers a generic dispatcher callback that calls async_write_ha_state() for every dispatched event — it does not check the event type or specifically handle STATE_CONNECTED. Suppressing the signal during initial connect removes one redundant state write during setup, which is harmless.

Any consumer that currently waits for STATE_CONNECTED during initial connect can simply check device.is_connected or connection.state after await connect() returns, which is both simpler and more reliable.

Tests

  • Updated all existing tests that waited for STATE_CONNECTED during initial connect to assert connection.state directly instead
  • Added test_connect_does_not_dispatch_connected to explicitly verify the signal is not dispatched on initial connect

Move the STATE_CONNECTED dispatch from _connect() to _reconnect() so that the signal only fires after auto-reconnect, not during initial connect().

During initial connect, the signal is redundant since the caller already knows the connection succeeded from the await returning. Dispatching it forces consumers to distinguish initial connect from reconnect with guard flags.

Update all tests that previously waited for STATE_CONNECTED during initial connect to instead assert connection.state directly.

Add test_connect_does_not_dispatch_connected to explicitly verify the signal is not dispatched on initial connect.
Copy link
Copy Markdown
Owner

@SteveEasley SteveEasley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense and LGTM 👍

@SteveEasley SteveEasley merged commit b6912ba into SteveEasley:main Apr 5, 2026
0 of 4 checks passed
SteveEasley pushed a commit that referenced this pull request May 6, 2026
PR #18 (Refresh device state after auto-reconnect) added two tests that
wait on `connect_signal` (STATE_CONNECTED) after the initial connect.
PR #19 (Dispatch STATE_CONNECTED only on auto-reconnect) then moved the
STATE_CONNECTED dispatch out of `_connect()` and into `_reconnect()`.
PR #19 updated other tests with the same pattern, but #19 was opened
before #18 merged, so the two tests added by #18 weren't updated.

Result: `await connect_signal.wait()` after initial connect waits
forever, hanging CI for the full 6h job timeout. Every CI run on main
since #18 has been cancelled this way (#19, #20, #21, v1.1.6, #22).

Match the pattern used by other tests updated in #19: assert
`state == STATE_CONNECTED` directly after the initial connect, and
keep `connect_signal.wait()` only for the post-reconnect signal where
STATE_CONNECTED is actually dispatched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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