20  Bluetooth Implementations and Labs

In 60 Seconds

BLE implementation requires mastering three layers: scanning and advertising (device discovery), GATT services (data exchange via services and characteristics), and power optimization (connection intervals and scan duty cycling). Common pitfalls include not waiting for MTU negotiation, using continuous scanning on battery gateways, and treating RSSI as exact distance.

Key Concepts
  • BLE HAL (Hardware Abstraction Layer): Platform-specific low-level driver interfacing the BLE controller chip with the host OS or RTOS scheduler
  • GATT Server: Device hosting BLE services and characteristics that clients can discover, read, write, and subscribe to; typically the sensor/peripheral
  • GATT Client: Device initiating service discovery and reading/writing characteristics on a GATT server; typically the gateway or smartphone
  • BLE Bonding Database: Non-volatile storage (NVS on ESP32, bond store on nRF) containing LTK, IRK, CSRK, and CCCD state for each bonded peer
  • Connection Event: Scheduled time slot when master and slave exchange packets; the fundamental unit of BLE connection-state communication
  • Channel Selection Algorithm #2 (CSA#2): BLE 5.0 algorithm for selecting data channels using a pseudo-random hash function, providing better channel distribution than the BT4.x LE CSA#1
  • LE Power Control: BLE 5.4 feature allowing real-time TX power adjustment based on RSSI feedback, optimizing power consumption for varying link conditions
  • Bluetooth Qualification: Mandatory certification process by the Bluetooth SIG for any commercial product using Bluetooth; requires testing at a BQTF (Bluetooth Qualification Test Facility)
Minimum Viable Understanding

Master three BLE implementation layers: (1) scanning and advertising for device discovery, (2) GATT services for structured data exchange via services and characteristics, and (3) power optimization through connection intervals and scan duty cycling. Avoid these costly mistakes: always wait for MTU negotiation completion before sending large payloads, use windowed scanning (not continuous) on battery-powered gateways, and never treat RSSI as an exact distance – use zone-based proximity instead.

20.1 Learning Objectives

By the end of this section, you will be able to:

  • Implement BLE Applications: Build Python and embedded C applications for BLE scanning and connectivity
  • Configure GATT Services: Create custom services and characteristics for IoT sensor data
  • Demonstrate BLE Event Handling: Program connection, disconnection, and notification callbacks
  • Diagnose BLE Communication Issues: Use packet sniffers and diagnostic tools for troubleshooting
  • Calculate and Apply Power Optimization: Select connection intervals and advertising strategies for target battery life
  • Construct End-to-End Solutions: Design and build complete BLE sensor-to-cloud data pipelines
  • Evaluate Scan Duty Cycle Trade-offs: Analyze detection probability versus power consumption for given deployment requirements
  • Distinguish MTU Negotiation Phases: Justify why payloads must not be sent before the exchange completion callback

What is this section? Practical implementation exercises for Bluetooth Low Energy (BLE) development, organized into focused chapters.

When to use:

  • After understanding BLE fundamentals and GATT profiles
  • When ready to write actual BLE code
  • Before building your own BLE IoT project

Prerequisites:

  • Basic programming knowledge (C/Python)
  • Understanding of BLE concepts from fundamentals chapter
  • Access to BLE-capable hardware or simulator

Recommended Path:

  1. Review Bluetooth Fundamentals
  2. Work through the chapters below in order
  3. Test understanding with Bluetooth Review

“Theory is great, but now it is time to write actual code!” said Max the Microcontroller, opening his development environment. “BLE implementation has three layers you need to master: scanning and advertising for discovery, GATT services for data exchange, and power optimization for long battery life.”

Sammy the Sensor asked, “Where do I start?” Max recommended, “Begin with code examples – simple BLE servers and clients that you can run in a simulator. Then move to Python dashboards that connect to your BLE devices. Finally, tackle the advanced labs like indoor positioning and mesh networking.”

“Watch out for the common traps,” warned Lila the LED. “The biggest one is forgetting about MTU negotiation. The default BLE packet size is only 20 bytes, but after MTU negotiation, you can send up to 247 bytes per packet. If you try to send 100 bytes without negotiating first, your data gets silently truncated!”

Bella the Battery added her concerns. “And please do not use continuous scanning on my battery-powered gateways! Scanning draws almost as much power as transmitting. Use windowed scanning – scan for 100 milliseconds, sleep for 900 milliseconds. That cuts my power consumption by 90 percent while still catching most advertisements.”

20.2 Chapter Overview

This implementation guide is organized into three focused chapters:

20.2.1 BLE Code Examples and Simulators

Estimated time: 45 minutes

Get started with BLE development through working code examples:

  • Python BLE scanner using bleak library
  • Arduino ESP32 GATT server implementation
  • Interactive Wokwi simulators for hands-on practice
  • GATT structure (services, characteristics, descriptors)
  • BLE development stack overview

20.2.2 BLE Python Implementations

Estimated time: 60 minutes

Production-ready Python code for common BLE tasks:

  • Device filtering by RSSI and name patterns
  • GATT service exploration and characteristic reading
  • iBeacon and Eddystone beacon parsing
  • Zone-based proximity detection with RSSI smoothing
  • Power optimization decision framework

20.2.3 BLE Hands-On Labs

Estimated time: 2-3 hours

Complete project implementations:

  • Lab 1: ESP32 Heart Rate Monitor (standard GATT service)
  • Lab 2: Python Environmental Dashboard (real-time monitoring)
  • Lab 3: Indoor Positioning System (beacon trilateration)
  • Lab 4: Mesh Network Simulation (message flooding)
  • Worked examples: MTU optimization and power budget analysis

20.3 Common BLE Implementation Pitfalls

Pitfall: Sending Data Immediately After MTU Exchange Without Waiting for Completion

The Mistake: Requesting MTU exchange and then immediately sending large payloads using the requested (but not yet negotiated) MTU size, resulting in data truncation, protocol errors, or silent data loss.

Why It Happens: MTU exchange is an asynchronous operation. The request returns immediately, but the actual negotiated MTU is only valid after the exchange completes (indicated by a callback or event). Developers often assume the requested MTU is granted and start using it before confirmation.

The Fix: Always wait for the MTU exchange completion callback before using the new MTU. Track the effective MTU and fall back gracefully:

// WRONG: Using requested MTU immediately
void on_connected(uint16_t conn_handle) {
    ble_gattc_mtu_exchange_request(conn_handle, 247);
    // BUG: MTU not yet negotiated!
    send_large_payload(conn_handle, data, 244);  // May truncate to 20 bytes!
}

// CORRECT: Wait for MTU exchange completion
volatile uint16_t g_effective_mtu = 23;  // Start with default

void on_connected(uint16_t conn_handle) {
    g_effective_mtu = 23;  // Reset to default
    ble_gattc_mtu_exchange_request(conn_handle, 247);
    // Don't send large data yet
}

void on_mtu_exchanged(uint16_t conn_handle, uint16_t negotiated_mtu) {
    g_effective_mtu = negotiated_mtu;
    uint16_t max_payload = g_effective_mtu - 3;  // ATT header overhead
    log_info("MTU negotiated: %d, max payload: %d", g_effective_mtu, max_payload);

    // NOW safe to send large payloads
    if (pending_large_transfer) {
        start_transfer_with_mtu(conn_handle, max_payload);
    }
}

Note: The negotiated MTU is the minimum of what both sides support. A 247-byte request may result in 185 bytes if the central only supports that.

Pitfall: Using Continuous Scanning Without Duty Cycling on Battery-Powered Gateways

The Mistake: Running BLE scanning with 100% duty cycle (scan window = scan interval) on a battery-powered gateway or hub device, expecting to catch all advertisements while draining the battery in hours instead of days.

Why It Happens: Developers want to ensure no advertisements are missed, so they maximize scan window. But BLE scanning consumes 5-15mA continuously - comparable to active Wi-Fi. For mains-powered gateways this is fine, but battery-powered devices suffer severely.

The Fix: Calculate the trade-off between scan duty cycle and advertisement detection probability. For most beacons, 10-30% duty cycle catches >95% of advertisements:

Scan parameter trade-offs:

100% duty cycle (continuous):
- Scan interval: 100ms, Window: 100ms
- Current: 12mA continuous
- Detection: ~100% (all advertisements)
- Battery life: 200mAh / 12mA = 17 hours

30% duty cycle (balanced):
- Scan interval: 100ms, Window: 30ms
- Current: ~4mA average
- Detection: >95% (for 100ms+ advertising intervals)
- Battery life: 200mAh / 4mA = 50 hours

10% duty cycle (power-optimized):
- Scan interval: 1000ms, Window: 100ms
- Current: ~1.5mA average
- Detection: >90% (for 1s+ advertising intervals)
- Battery life: 200mAh / 1.5mA = 133 hours

Consider your beacon advertising interval when tuning scan parameters - you don’t need 100% duty cycle if beacons advertise frequently.

Calculating scan duty cycle vs advertisement detection probability:

A BLE gateway scans for beacons that advertise every 1000 ms. What scan duty cycle is needed to catch >95% of advertisements?

Beacon advertising:

  • Advertising interval: 1000 ms (1 second)
  • Advertisement duration: ~2 ms (includes 3 advertising channels)

Scanner with 10% duty cycle:

  • Scan interval: 1000 ms
  • Scan window: 100 ms
  • Probability of catching advertisement: $ P_{} = = = 0.102 = 10.2% $

Wait, that’s not right. Let me recalculate properly:

For a beacon advertising every 1000 ms with 2 ms advertisement duration, a scanner with scan window of 100 ms will catch it if the advertisement falls within any of the scan windows.

Since beacon advertisements happen at random offsets within the 1000 ms interval (due to ± 10ms randomization), the probability is: $ P_{} = = = 10% $

But we scan every second, so over 10 scan intervals (10 seconds): $ P_{} = 1 - (1 - 0.10)^{10} = 1 - 0.35 = 65% $

For >95% detection within 3 seconds, we need:

Let scan window be \(w\), with scan interval = 1000 ms. For 3 scans to have >95% cumulative detection: $ 1 - (1 - )^3 $

Solving: $ (1 - )^3 - $

Therefore \(w \geq 632\) ms. This means 63% duty cycle is needed for 95% detection within 3 seconds.

Power comparison (12 mA scan current, 2 mA idle):

100% duty cycle: 12 mA continuous 63% duty cycle: \((12 \times 0.63) + (2 \times 0.37) = 7.56 + 0.74 = 8.3\) mA 10% duty cycle: \((12 \times 0.10) + (2 \times 0.90) = 1.2 + 1.8 = 3.0\) mA

The 10% duty cycle reduces power by 64% \((1 - 3.0/8.3)\) compared to 63% duty cycle, but detection latency increases from 3 seconds to ~10 seconds.

Adjust scan parameters and beacon advertising interval to calculate detection probability and power consumption.

The Misconception: Many developers believe RSSI (Received Signal Strength Indicator) values can be directly converted to precise distances using simple formulas, and use raw RSSI readings for positioning without filtering.

Why This Fails (With Data):

1. RSSI Variance at Fixed Distance:

  • At 2 meters: RSSI can vary +/-8 dBm (range: -58 to -74 dBm)
  • Translation: Same physical position = 1.4m to 5.0m estimated distance
  • Error rate: Up to 150% distance error without filtering

2. Environmental Interference:

  • Human body: -5 to -15 dBm attenuation (doubles estimated distance)
  • Wall penetration: -10 to -30 dBm loss depending on material
  • Multipath fading: +/-6 dBm variance from reflections

The Correct Approach:

For Positioning:

  • Use zone-based proximity: Immediate (<0.5m), Near (0.5-3m), Far (>3m)
  • Require 3+ beacon measurements: Trilateration needs redundancy
  • Calibrate per environment: Measure path loss exponent (n) on-site
  • Apply time averaging: 5-10 samples over 2-5 seconds

Zone thresholds: Use >-60 dBm (immediate), -60 to -75 dBm (near), <-75 dBm (far)

20.3.1 Knowledge Check: BLE Scan Duty Cycling

20.3.2 Knowledge Check: MTU Exchange Timing

Question: What connection interval and peripheral latency should you use for your BLE device?

The Trade-off: Connection interval determines how often the central and peripheral communicate. Shorter intervals provide lower latency but consume more power. Peripheral latency allows devices to skip connection events to save power.

Application Type Connection Interval Peripheral Latency Supervision Timeout Rationale
Gaming Controller 7.5-15ms 0 500-1000ms Minimum latency critical, power less important (rechargeable)
Wireless Keyboard/Mouse 15-30ms 0 1000ms Responsive input, USB HID requires <10ms total latency
Fitness Tracker (Active) 30-50ms 0 2000ms Real-time heart rate display during workout
Fitness Tracker (Idle) 100-400ms 4-10 4000-6000ms Power optimization when no activity detected
Smart Lock 50-100ms 0 2000ms Fast unlock response required for UX
Temperature Sensor (Slow) 500-1000ms 4-10 8000-10000ms Temperature changes slowly, maximize battery
Industrial Vibration Sensor 50-100ms 0 2000ms High-frequency sampling, needs reliability
Asset Tracking Beacon 1000-4000ms 10-20 16000-32000ms Position updates every few seconds sufficient

Selection Rules:

  1. Start with application latency requirement:
    • Real-time control (<50ms): Use 7.5-30ms interval
    • Interactive feedback (50-200ms): Use 30-100ms interval
    • Periodic monitoring (>200ms): Use 100-1000ms+ interval
  2. Apply peripheral latency for power optimization:
    • Formula: latency = (desired_update_interval / connection_interval) - 1
    • Example: Want 1-second updates with 100ms interval → latency = (1000/100) - 1 = 9
    • Constraint: iOS limits latency × interval ≤ 2 seconds
  3. Calculate supervision timeout:
    • Formula: timeout > (1 + latency) × interval × 2
    • Example: CI=100ms, latency=9 → timeout > (1+9) × 100ms × 2 = 2000ms
    • Use 4000ms for safety margin
  4. Verify iOS compatibility:
    • Interval: 15ms - 2000ms (Apple requires multiples of 15ms)
    • Latency: Max 30
    • Timeout: 2000ms - 6000ms
    • If outside range, iOS will silently modify parameters

Example Decision Process:

Scenario: Smart thermostat that displays temperature and allows user to adjust settings.

Requirements:
- Temperature updates: Every 5 seconds
- Button response: <200ms when user adjusts
- Battery life: 2+ years on 2× AA batteries

Design:
- Base interval: 100ms (allows <200ms response)
- Peripheral latency: 49 (allows 5-second temperature updates)
  → Device responds every 50th event = 5000ms
  → Button press forces immediate response (skip latency)
- Supervision timeout: (1 + 49) × 100ms × 2 = 10,000ms

Result:
- Button response: 100ms average (responsive UX)
- Temperature update: 5 seconds (meets requirement)
- Radio duty cycle: 2% (50× reduction vs no latency)
- Battery life: 2+ years achieved

Key Insight: Don’t use a single connection interval for all use cases. Match the interval to your latency requirement, then use peripheral latency to save power during idle periods. Always test on iOS devices to catch parameter override issues.

20.3.3 Knowledge Check: BLE Connection Interval Selection

Worked Example: RSSI Calibration for Indoor Positioning System

Scenario: A museum deploys BLE beacons for visitor wayfinding. Initial deployment shows 5+ meter position errors. The team needs to calibrate RSSI-to-distance conversion for their specific environment.

Given:

  • Beacon hardware: Estimote Location Beacons, TX power = +4 dBm
  • Environment: Open gallery space with marble floors and 5-meter ceilings
  • Initial path loss exponent assumed: n = 2.0 (free space)
  • Reference RSSI at 1 meter (from datasheet): -59 dBm
  • Measured RSSI samples at known distances (10 samples each):
    • 1 meter: -61 dBm average, std dev = 2.1 dBm
    • 2 meters: -68 dBm average, std dev = 3.4 dBm
    • 4 meters: -76 dBm average, std dev = 4.2 dBm
    • 8 meters: -84 dBm average, std dev = 5.8 dBm

Steps:

  1. Calculate measured path loss at each distance:
    • PL(1m) = TxPower - RSSI = 4 - (-61) = 65 dB (reference)
    • PL(2m) = 4 - (-68) = 72 dB, expected free space: 65 + 20log(2) = 71 dB
    • PL(4m) = 4 - (-76) = 80 dB, expected free space: 65 + 20log(4) = 77 dB
    • PL(8m) = 4 - (-84) = 88 dB, expected free space: 65 + 20log(8) = 83 dB
  2. Fit path loss exponent using regression:
    • Path loss model: PL(d) = PL(d0) + 10 x n x log10(d/d0)
    • Using d0 = 1m, PL(d0) = 65 dB
    • Linear regression on log10(distance) vs path loss:
    • Slope = 10n = 28.3, therefore n = 2.83
  3. Update distance formula with calibrated values:
    • Old formula: d = 10^(((-59) - RSSI) / 20) (assumed n=2.0)
    • Calibrated formula: d = 10^(((-61) - RSSI) / 28.3) (n=2.83)
  4. Validate calibration with test points:
    • At RSSI = -72 dBm:
    • Old estimate: 10^((-59-(-72))/20) = 4.5 meters (error: +1.5m)
    • Calibrated: 10^((-61-(-72))/28.3) = 2.8 meters (actual: 3.0m, error: -0.2m)

Result: After calibration, positioning error reduced from 5+ meters to 1.8 meters average. The museum environment has path loss exponent n=2.83 (vs. 2.0 assumed), likely due to marble floor reflections increasing signal absorption.

Key Insight: Never use datasheet RSSI values for production positioning. Every environment has unique path loss characteristics. A one-time 15-minute calibration walk (measuring RSSI at 4-6 known distances) can improve accuracy by 60-70%.

Worked Example: BLE Beacon Density Optimization for Zone Detection

Scenario: A retail store wants to trigger personalized offers when shoppers enter specific departments. The goal is 85% zone detection accuracy (shopper in correct 10m x 10m zone) while minimizing beacon count and cost.

Given:

  • Store floor area: 2,000 square meters (50m x 40m)
  • Zone size: 10m x 10m (20 zones total)
  • Target accuracy: 85% correct zone identification
  • Beacon cost: $25 per beacon (including installation)
  • BLE range: ~30 meters (but RSSI unreliable beyond 10m)

Steps:

  1. Calculate baseline beacon density:
    • For zone-level accuracy, need 3+ beacons visible from each point
    • Basic grid: 1 beacon per zone center = 20 beacons
    • Detection rate with single beacon per zone: ~65% (RSSI variance causes mis-classification)
  2. Model zone boundary ambiguity:
    • At zone boundary (5m from two beacons), RSSI difference is minimal
    • RSSI at 5m: approximately -70 dBm (+/-4 dBm variance)
    • Probability of correct classification at boundary: 50% (random)
    • 30% of floor area is within 2m of zone boundary
  3. Add boundary beacons:
    • Place additional beacons at zone corners (shared by 4 zones)
    • Grid intersections: 6 x 5 = 30 beacons
    • Each point now sees 4 beacons minimum
    • Zone classification uses weighted voting from all visible beacons
  4. Calculate detection rate with boundary beacons:
    • Interior points (70% of area): 95% correct (strong RSSI difference)
    • Boundary points (30% of area): 70% correct (4-beacon voting)
    • Overall: 0.70 x 0.95 + 0.30 x 0.70 = 66.5% + 21% = 87.5%
  5. Optimize cost vs accuracy:
    • Option A: 20 beacons (center only) = $500, 65% accuracy
    • Option B: 30 beacons (intersections) = $750, 87.5% accuracy
    • Option C: 50 beacons (center + intersections) = $1,250, 92% accuracy
    • Recommendation: Option B meets 85% target at lowest cost

Result: Deploy 30 BLE beacons at zone corner intersections, achieving 87.5% zone detection accuracy for $750 total cost ($37.50 per zone).

Key Insight: For zone-based applications, beacon placement at zone boundaries (intersections) is more effective than zone centers. A beacon at the intersection of 4 zones contributes to classification accuracy for all 4 zones, while a center beacon only helps its own zone.

20.5 Summary

This section provides comprehensive BLE implementation guidance through three focused chapters:

  • Code Examples: Working Python and ESP32 code with interactive Wokwi simulators
  • Python Implementations: Production-ready scanner, GATT explorer, beacon manager, and proximity detector
  • Hands-On Labs: Complete projects for heart rate monitoring, dashboards, positioning, and mesh networks

Key implementation principles to carry forward: always await the MTU exchange completion callback before sending large payloads; apply scan duty cycling on battery-powered gateways; calibrate RSSI-to-distance conversion in the target environment; and match connection intervals to the latency requirements of each application.

20.6 What’s Next

Chapter Description Why Read It
BLE Code Examples and Simulators Python bleak scanner and ESP32 GATT server with Wokwi simulations Start here — run BLE code in a browser simulator before touching hardware
BLE Python Implementations Production-ready beacon parser, GATT explorer, and proximity detector Build real gateway software with iBeacon/Eddystone parsing and RSSI filtering
BLE Hands-On Labs Four complete projects: heart rate monitor, dashboard, IPS, mesh network End-to-end lab practice covering all major BLE application patterns
Bluetooth Fundamentals and Architecture BLE protocol stack, GATT hierarchy, advertising channels Review theory if implementation concepts feel unclear
Bluetooth Security Pairing modes, LE Secure Connections, key management Secure your implementations before deploying to production
Bluetooth Comprehensive Review MCQs and worked examples covering the full Bluetooth module Validate all implementation knowledge before moving to the next module