Summary
oura scan silently drops any peripheral that advertises without a local name. Since a ring that is bonded to the official Oura app commonly advertises with no local_name, the very first command a new user runs reports "No Oura rings found." while the ring is sitting a foot away.
Cause
crates/oura-link/src/ble.rs:66-69
let name = props.local_name.unwrap_or_default();
if !name.to_lowercase().contains(&name_contains.to_lowercase()) {
continue;
}
With the default --name Oura, a missing local_name becomes "", and "".contains("oura") is false, so the device is skipped with no output.
The same filter runs at ble.rs:114-117, on the connect path — and there it is applied before the --address check at ble.rs:118-120. So --address <id> alone does not work around it either; you must also pass --name "".
Reproduce
Ring 4, bonded to the official app, macOS 26.5, btleplug 0.11, HEAD c5106bd:
$ oura scan
No Oura rings found.
$ oura scan --name "" --scan-timeout 40
-60 dBm (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)
One device, strong RSSI, empty name field — the ring, excluded by the default filter.
Suggested fix
Keep unnamed peripherals when the user has not explicitly narrowed the search, so discovery degrades to "show me what's there" rather than to silence:
let name = props.local_name.unwrap_or_default();
if !name_contains.is_empty()
&& !name.is_empty()
&& !name.to_lowercase().contains(&name_contains.to_lowercase())
{
continue;
}
Alternatives that would also solve it, if you would rather not widen the default:
- Filter on the Oura service UUID instead of the advertised name — robust regardless of whether a name is present.
- Have the empty result mention the filter:
No devices matching "Oura". Try --name "" to list everything. That alone would have saved the debugging session.
- Apply
--address before --name on the connect path, so an explicit address bypasses name filtering.
Related, possibly worth its own issue
There appears to be no timeout on the request/response path. ble.rs sets deadlines for scanning (ble.rs:47, ble.rs:103) but the notification pump (ble.rs:166-171) has none, so if a ring accepts the connection and then never replies, oura info hangs indefinitely with no error or diagnostic. Happy to file that separately if useful.
Thanks for open-sourcing this — the protocol work is impressive, and everything above is from a first-hour attempt to get a Ring 4 talking.
Summary
oura scansilently drops any peripheral that advertises without a local name. Since a ring that is bonded to the official Oura app commonly advertises with nolocal_name, the very first command a new user runs reports "No Oura rings found." while the ring is sitting a foot away.Cause
crates/oura-link/src/ble.rs:66-69With the default
--name Oura, a missinglocal_namebecomes"", and"".contains("oura")isfalse, so the device is skipped with no output.The same filter runs at
ble.rs:114-117, on the connect path — and there it is applied before the--addresscheck atble.rs:118-120. So--address <id>alone does not work around it either; you must also pass--name "".Reproduce
Ring 4, bonded to the official app, macOS 26.5,
btleplug 0.11, HEADc5106bd:One device, strong RSSI, empty name field — the ring, excluded by the default filter.
Suggested fix
Keep unnamed peripherals when the user has not explicitly narrowed the search, so discovery degrades to "show me what's there" rather than to silence:
Alternatives that would also solve it, if you would rather not widen the default:
No devices matching "Oura". Try --name "" to list everything.That alone would have saved the debugging session.--addressbefore--nameon the connect path, so an explicit address bypasses name filtering.Related, possibly worth its own issue
There appears to be no timeout on the request/response path.
ble.rssets deadlines for scanning (ble.rs:47,ble.rs:103) but the notification pump (ble.rs:166-171) has none, so if a ring accepts the connection and then never replies,oura infohangs indefinitely with no error or diagnostic. Happy to file that separately if useful.Thanks for open-sourcing this — the protocol work is impressive, and everything above is from a first-hour attempt to get a Ring 4 talking.