Skip to content

[bluetooth.generic] Only poll linked characteristics and recover without dropping intent - #21529

Draft
vkolotov wants to merge 2 commits into
openhab:mainfrom
vkolotov:vkolotov/bluetooth-generic-reconnect-and-linked-polling
Draft

[bluetooth.generic] Only poll linked characteristics and recover without dropping intent#21529
vkolotov wants to merge 2 commits into
openhab:mainfrom
vkolotov:vkolotov/bluetooth-generic-reconnect-and-linked-polling

Conversation

@vkolotov

@vkolotov vkolotov commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

This is a supporting PR for a larger project (new bluetooth binding for direct access).

Four fixes to the generic binding's characteristic polling job, plus the core API change one of them needs. Each behaviour change sits behind a binding config switch that defaults to the new behaviour, so it can be turned off if it misbehaves on some device or transport.

  1. Poll only linked characteristics.

  2. Recover unresolved services without dropping connection intent. When a device is connected but its GATT services never resolve, the job bounced the link with disconnect(), which is also how a handler says it no longer wants the device connected. A transport that tracks intent cannot tell the two apart and reads the recovery as a request to stop connecting, so it flaps.

  3. Guard the tick body. An uncaught RuntimeException from a transport call cancells the repeating job, and polling then stopped and nothing in the logs.

  4. Also polls once as soon as service discovery completes, rather than leaving a freshly resolved device idle until the next scheduled tick.

… intent

A handler that is connected but has not been able to resolve the GATT
services recovers by bouncing the link and retrying service discovery. The
only way to express that was disconnect(), which is also how a handler says
"I no longer want this device connected".

A transport that tracks connection intent (to keep an alwaysConnected device
connected, for example) cannot tell the two apart, and reads the recovery
attempt as a request to stop connecting. The result is a connect/disconnect
flap.

Add BluetoothDevice#reconnect() for the recovery case. The default
implementation delegates to disconnect(), so transports that do not track
intent keep their current disconnect-then-reconnect behaviour unchanged.

Signed-off-by: Vlad Kolotoff <vkolotoff@pm.me>
…out dropping intent

Three related fixes to the characteristic polling job, each behind a binding
config switch that defaults to the new behaviour and can be turned off to
restore the old one.

Poll only linked characteristics. The job read every readable characteristic
on every tick, whether or not the channel had a linked item, which is
needless GATT traffic on the device. Notification enable/disable already
tried to key off links, but used isLinked(), which the existing TODO in the
code notes reports true for channels that are not linked. Use
ItemChannelLinkRegistry#getLinkedItemNames() instead, and apply the same test
to reads. Switch: pollOnlyLinkedCharacteristics.

Recover unresolved services with reconnect() rather than disconnect(), so a
transport that tracks connection intent does not read the recovery as "stop
wanting this device" and flap. Switch: reconnectOnUnresolvedServices.

Guard the tick body. An uncaught RuntimeException from a transport call would
cancel the repeating job, and polling then stopped for good with nothing in
the log. Catch and log instead, so the next tick retries.

Also poll once as soon as service discovery completes, instead of leaving a
freshly resolved device idle until the next scheduled tick, which is up to a
full polling interval of dead air after every reconnect.

Signed-off-by: Vlad Kolotoff <vkolotoff@pm.me>
@vkolotov
vkolotov force-pushed the vkolotov/bluetooth-generic-reconnect-and-linked-polling branch from 470864b to 6e163cb Compare August 29, 2026 06:09
@vkolotov
vkolotov marked this pull request as ready for review August 29, 2026 06:17
@vkolotov
vkolotov marked this pull request as draft August 29, 2026 12:34
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