BLE Scanning Reliability: Duplicate Filtering, RSSI Windows and Missed Advertisements

A quiet BLE scan callback can mean several things: no matching packet was received, the controller suppressed a duplicate, the operating system delayed delivery, or application code discarded an update. These explanations require different fixes. Define the observation you need before increasing scan duty cycle or declaring the peripheral out of range.

For qualification, consult the SIG’s Core 6.0 page and its mandatory updates. This engineering guide is not a compliance checklist.

Scope: this guide concerns connectionless observation of legacy BLE advertisements. Bluetooth Core 6.0 and Zephyr 3.7.0 provide the protocol and embedded-API baseline; Android API references illustrate application reporting. These versions are explicit boundaries, not a latest-version claim. Sources were checked on 11 October 2026. Examples and diagrams are analytical proposals, not measured reception or ranging results.

Choose a metric with a known denominator

For onboarding, measure time from scan activation to the first eligible report. For a device list, measure freshness of available evidence and stability of displayed rows. For payload monitoring, measure how many distinct application sequence values arrive. These are different outcomes; a scanner can discover reliably while delivering few repeated reports.

A packet-loss percentage needs a defensible transmitted-packet count, compatible timestamps and a defined channel/PHY scope. Counting callbacks against a nominal advertising interval does not provide that denominator. A single advertising event may produce multiple over-the-air transmissions, while software can merge or suppress reports. Use an instrumented transmitter or suitable capture reference when the actual loss rate matters.

Understand the requested listening schedule

Core 6.0 Link Layer section 4.4.3 defines scan interval as the spacing between window starts; the window cannot exceed the interval. Channel selection and scheduling conflicts also matter. Setting equal values requests continuous scanning, not guaranteed reception of every advertisement.

As a worked configuration, a 120 ms interval and 30 ms window have a nominal 25 percent listening ratio. In Zephyr 3.7.0, both fields use 0.625 ms units, so the corresponding values are 192 and 48. The ratio is arithmetic, not a 25 percent discovery probability: packet timing, channel overlap, interference and competing radio work change the outcome.

Conceptual BLE timeline with 30 millisecond scan windows every 120 milliseconds, followed by controller, operating-system and application filtering gates before UI updates.
Original explanatory timeline. Window overlap is necessary in this simplified view; successful decoding and report delivery remain separate gates.

Separate three kinds of filtering

Controller duplicate filtering, host or operating-system delivery policy, and app-level row deduplication operate at different boundaries. In the Core 6.0 legacy model, duplicate classification can be based on advertiser address during the scanning state; changing payload bytes does not necessarily make a new report. Advertising and scan-response reports are considered separately. Therefore, a changing sensor byte cannot be assumed to bypass controller filtering.

On an embedded scanner, compare runs with BT_LE_SCAN_OPT_FILTER_DUPLICATE enabled and disabled while leaving other parameters unchanged. Keep the filter accept list unchanged too: selecting allowed advertisers is a different operation from suppressing repeated reports. On a phone, document the API options actually available rather than assuming direct controller control.

Android additionally exposes report batching through ScanSettings.Builder. Preserve the observation timestamp where available; ScanResult reports a timestamp since boot. Callback arrival time and observation time should occupy separate columns. Never subtract a boot-relative timestamp from a wall-clock date.

Deduplicate presentation without erasing evidence

Maintain a bounded observation record before application-level deduplication. Suggested fields are scan-session ID, observation time, callback arrival time, address and address type where exposed, packet/report kind, parsed payload version, RSSI and parser outcome. Keep raw identifiers only where justified for the test and remove them from routine user analytics.

Then update a separate device-list model. Multiple reports may legitimately refer to one displayed row. Preserve last-observed time and sample count even when the name and product class remain unchanged. However, “before app deduplication” still means after any controller or OS suppression. A stale timestamp under duplicate filtering is insufficient evidence that radio reception stopped.

Address changes need an explicit identity policy. A name is unsuitable as a unique key because separate devices can share it. For an unassociated device, retain an uncertain candidate rather than merging observations merely because RSSI and names look similar. Test two identical products side by side; accidental merging can masquerade as missed advertisements.

Use RSSI windows for stability, not a distance promise

RSSI describes received signal strength. Inferring distance requires a model and validation for the installation; a single threshold cannot remove orientation, enclosure or propagation effects. Bluetooth SIG’s security and privacy guidance also cautions that signal-strength-based proximity is not a secure proof of distance.

For a proposed UI policy, maintain a five-second window, require at least five valid observations, and display its median RSSI with sample count and newest-sample age. These numbers are illustrative, to be tuned for the product. Use separate enter and exit thresholds with dwell times if a categorical “nearby” indicator is necessary. Label it as a signal category unless ranging accuracy has actually been established.

Discard documented invalid RSSI values instead of averaging them. When too few samples exist, return “insufficient observations”; do not fill missing intervals with an invented weak signal. Evaluate the window against recorded traces before testing motion, so a state-machine error is not confused with changing RF conditions.

Run paired experiments and publish the limits

  1. Fix firmware, transmit power, position, orientation, advertising mode and payload. Record scanner/controller versions and all scan options.
  2. Establish a stationary baseline with a bounded scan session. Compare duplicate filtering on and off without changing duty cycle.
  3. Vary window or interval one at a time. Report discovery latency distributions and scans with no discovery within the observation period.
  4. Repeat under realistic interference and motion. Keep the stationary control so environmental changes remain visible.
  5. Replay identical, changed-payload, malformed and same-name-device records through app logic. Verify parser, freshness and display behavior separately.
  6. Confirm cancellation and scan failures appear as explicit outcomes rather than timeouts attributed to the peripheral.

Acceptance should state a supported environment, a discovery target and an allowed failure rate established by real measurements. Until those measurements exist, publish the test method and uncertainty. A reliable scanner explains the difference between absent evidence, filtered evidence and evidence that was received but not displayed.

Similar Posts