Acknowledged
CIQQA-4786

fēnix 8: BLE scan drops advertisements from Resolvable Private Addresses of unpaired peripherals (public and static addresses work)

Device: fēnix 8 Solar 47mm (006-B4532-00), firmware 23.39, Connect IQ 6.0.2 / API 6.0.3
SDK: 9.2.0
App type: watch-app

Summary

A connectable peripheral that advertises from a Resolvable Private Address never appears in onScanResults(). The exact same advertising payload sent from a public/static address is delivered normally. So the filtering seems to depend on the address type, not on the payload.

Peripheral

Panasonic LUMIX S5M2 camera. When switched on it advertises ADV_IND (legacy PDU, connectable, scannable) from a Resolvable Private Address. When switched off (Bluetooth standby) it advertises from its public address. The payload is the same in both cases except for one state byte:

02 01 06 | 09 FF 3A 00 00 xx xx xx xx xx | 11 07 1B C5 D5 A5 02 00 0D AC E6 11 14 32 20 C6 4A 05

Scan response: Complete Local Name.

What the app does

  • Registers two profiles (registerProfile, both return STATUS_SUCCESS): the advertised service 054AC620-3214-11E6-AC0D-0002A5D5C51B and the GATT service the app uses afterwards.
  • Starts scanning (SCAN_STATE_SCANNING).
  • Parses ScanResult.getRawData() itself. getDeviceName() and getManufacturerSpecificData() return null for every result on this device, but the raw data is complete.

Results

About 30 s scans, camera less than 1 m from the watch:

Advertiser Address type (per btmon) Seen by the watch
Camera ON Resolvable (e.g. 78:70:F5:xx:xx:xx) never (0 results across 6+ runs)
Camera in standby Public (7C:B8:DA:xx:xx:xx) yes (about 30 results / 30 s)
Linux PC (btmgmt add-adv) with identical payload, state byte 00 Public yes (4–10 results)
Phones/speakers nearby (Apple, Sonos) various yes (hundreds)

A Linux PC (BlueZ) and an Android phone see the camera in all states, and both can connect and use its GATT service without bonding, with MTU 23 and writes of at most 20 bytes. The watch-side flow is therefore expected to work if the scan result reaches the app.

Expected: advertisements from RPA peripherals are delivered to onScanResults() (maybe with the RPA as the address), so the app can pairDevice() with them.
Actual: they are silently dropped.

Questions

  1. Is this intended filtering (e.g. dropping unresolvable RPAs)? If so, is there a way to opt out?
  2. If it is a bug, is a fix planned for fēnix 8?

btmon logs and the test app source are available on request.

  • Thanks, Jim. I compared the flags as you suggested: they are not the cause. The camera uses the same flags (0x06) in standby, when the watch sees it, and when switched on, when it doesn't. My Android test advertisement uses flags 0x1a, exactly like the iPhone that the watch does see, and it is still never returned. Details below.

    This supersedes my previous reply. I tested this thoroughly and can now describe the issue precisely, and reproduce it without the camera. The original report still holds, with one refinement: RPAs from devices bonded with the watch are returned. Only RPAs from unpaired peripherals are dropped.

    SETUP

    • fēnix 8 Solar 47mm, firmware 23.39, scanning with BleScan.
    • Reference scanners: btmon on Linux (continuous scan, also from a random address) and nRF Connect on iOS.
    • Peripherals: Panasonic LUMIX S5II camera, an Android phone (Galaxy S9) advertising with nRF Connect, and my iPhone, which is paired with the watch.

    1. THE CAMERA

    • Camera off (standby): connectable legacy ADV_IND from its public address, every ~1.2 s. BleScan returns it every time (RSSI around −45).
    • Camera on: connectable legacy ADV_IND from a resolvable private address, every ~160 ms, so actually more often than in standby. BleScan never returns it, even with the camera right next to the watch and repeated scans over several minutes.
    • btmon shows the same PDU type, the same flags and the same 31-byte payload in both states. Only one state byte in the manufacturer data differs.
    • The RPA is valid: top bits 01, random part neither all zeros nor all ones.
    • The camera answers scan requests in both states, also from a scanner using a random address, so this is not about scan responses. BleScan shows Name: null for every device, so Connect IQ does not seem to use scan response data at all.
    • The camera was not connected to anything during the tests.

    2. REPRODUCTION WITH AN ANDROID PHONE

    • nRF Connect on Android → Advertiser: a connectable legacy advertisement with manufacturer data 0x003A / 001122334455 and the camera's 128-bit service UUID. Android advertises from an RPA.
    • nRF Connect on iOS sees it. The fēnix 8 never returns it.
    • After removing the 128-bit UUID, so that only the manufacturer data was left, the watch still never returned it. The payload content is not the cause.

    3. WHAT THE WATCH RETURNS

    Returned by BleScan:

    • Camera in standby: public address, not bonded → returned
    • Apple Find My beacons (4c 00 12): static random address, not bonded → returned
    • My iPhone (4c 00 10): resolvable private address, bonded → returned

    Never returned:

    • Camera switched on: resolvable private address, not bonded → not returned
    • Android phone (nRF Connect): resolvable private address, not bonded → not returned
    • Other Apple devices nearby (4c 00 10): resolvable private address, not bonded → not returned

    When I turned off Bluetooth on my paired iPhone, the last RPA advertisement disappeared from BleScan. The Apple Find My beacons from static addresses stayed. btmon and nRF Connect on iOS see several other Apple devices advertising connectable ADV_IND from RPAs at the same time, but none of them show up on the watch.

    CONCLUSION

    The fēnix 8 only passes on resolvable private addresses that it can resolve, i.e. from bonded devices, and silently drops RPAs from all unpaired peripherals. Public and static random addresses are not affected. It looks like the controller's resolving list / privacy mode filters unresolved RPAs before they reach Connect IQ.

    For Connect IQ apps this means they cannot discover most modern BLE peripherals before pairing. Phones, cameras and many newer sensors advertise from RPAs, and a Connect IQ app has no way to bond with them first.

    SIMPLE REPRODUCTION FOR THE TEAM

    1. On any Android phone, open nRF Connect → Advertiser and add a connectable legacy advertisement with some manufacturer data (Android advertises from an RPA).
    2. Confirm with another scanner that it is on air.
    3. Scan with a Connect IQ app on the fēnix 8: the advertisement never appears.

    I can share the btmon captures if they would be useful.

  • Use nRF connect and compare things like the flags in the Advertisement.  I suspect something  there that's not supported with CIQ

  • Thanks, Jim. I ran BleScan and dug a bit deeper, and I need to narrow my original claim.

    Camera switched off (standby): BleScan on the fēnix 8 finds it right away: 31-byte payload, service 054AC620-…, RSSI around −45. In this state the camera advertises a connectable legacy ADV_IND from its public address, roughly every 1.2 s (measured with nRF Connect).

    Camera switched on: BleScan never returns it, even with the camera lying next to the watch and repeated scans for about a minute. Only Sonos and Apple devices show up. In this state the camera advertises from a random resolvable address, about every 160 ms. A Linux btmon capture shows the same legacy ADV_IND, the same flags and the same 31-byte payload as in standby; only the one state byte in the manufacturer data differs. The camera is not connected to anything during the test.

    Correction: it is not all RPA advertisers. BleScan does return Apple “Nearby Info” advertisements, which are also connectable ADV_IND from resolvable addresses. So it is not a blanket RPA filter. Something specific about this device’s RPA advertisement makes the watch drop it, while the same advertisement from a public address gets through.

    If it helps the team, I can share the btmon captures or test a debug build.

  • Understand that with CIQ, you can only see about 30 bytes of raw data. You can see that with my BleScan app

  • Some background on why this matters to me: I'm building a Connect IQ app that turns the fēnix 8 into a GPS source for my Panasonic LUMIX camera (S5II). The watch connects to the camera over BLE and sends it the time and location every ~30 seconds, so every photo gets geotagged – no phone needed.

    Today this only works through the LUMIX Lab phone app, which keeps losing the connection in the background, so photos end up without GPS. The watch is always on my wrist during hikes and rides and already has an excellent GPS, so it's the perfect device for this.

    The protocol works: I have it running on Android and Linux. The only thing blocking it on the watch is this issue – a switched-on camera advertises from an RPA, so the watch never sees it. I'd also like to publish the app in the Connect IQ Store for other LUMIX owners.