/ #esp32 #ble 

Turn ESP32 Into a BLE Beacon Scanner for Presence Detection in Home Assistant

Before we begin: This guide assumes you have Home Assistant already set up and are comfortable with basic ESPHome configurations.

I’ve tried nearly every presence detection method in my smart home journey - from WiFi-based tracking that drained my phone battery to GPS solutions that were anything but reliable indoors. That’s when I discovered the magic of BLE beacon scanning with ESP32 for room-level presence detection. It’s been a game-changer for my home automations, and today I’ll show you exactly how to set it up.

Why BLE Beacon Scanning?

Bluetooth Low Energy (BLE) beacons (like those emitted by your phone, smartwatch, or dedicated tags) provide a perfect balance between precision and privacy for presence detection. Unlike GPS, it works flawlessly indoors. Unlike WiFi tracking, it doesn’t require your device to be connected to a network, saving battery life.

The best part? You probably already have multiple BLE beacons in your pocket right now - your smartphone constantly broadcasts these signals, just waiting to be detected!

What You’ll Need

Here’s the shopping list for this project:

Total cost: Under $15 if you’re just getting started!

Step 1: Preparing Your ESP32 with ESPHome

First, we need to get ESPHome installed on your ESP32. If you haven’t set up ESPHome with Home Assistant yet, check out my previous guide on ESP32 temperature monitoring for a detailed walkthrough.

Once you have ESPHome running, create a new device and use this configuration as your starting point:

esphome:
  name: esp32-ble-scanner
  platform: ESP32
  board: nodemcu-32s

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Enable logging for debugging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_encryption_key

ota:
  password: !secret ota_password

# Enable Bluetooth proxy for passive BLE scanning
bluetooth_proxy:
  active: true

# Sensor to track devices
sensor:
  - platform: ble_rssi
    mac_address: "AA:BB:CC:DD:EE:FF" # Replace with your device's MAC
    name: "Phone Bluetooth RSSI"
    id: phone_ble_rssi
    device_class: signal_strength
    unit_of_measurement: "dBm"
    accuracy_decimals: 0
    filters:
      - delta: 5.0 # Only send updates if RSSI changes by 5dBm

# Binary sensor for presence detection
binary_sensor:
  - platform: ble_presence
    mac_address: "AA:BB:CC:DD:EE:FF" # Replace with your device's MAC
    name: "Phone Presence"
    id: phone_presence
    device_class: presence

# Optional: Signal strength tracking for distance estimation
  - platform: template
    name: "Phone Nearby"
    lambda: |-
      if (id(phone_ble_rssi).state > -70) {
        return true; // Very close
      } else if (id(phone_ble_rssi).state > -85) {
        return true; // In room
      } else {
        return false; // Not nearby
      }      
    filters:
      - delayed_off: 30s # Prevents flapping when walking between rooms

# Text sensor to see all detected devices (great for debugging)
text_sensor:
  - platform: ble_scanner
    name: "BLE Devices"
    id: ble_devices
    expiry: 300 # Remove devices not seen for 5 minutes
Pro tip: Finding your device's MAC address can be tricky. On Android, check Settings > About Phone > Status. On iPhone, it's buried in Settings > General > About > Bluetooth. Some devices use randomized MAC addresses for privacy - you might need to disable this feature for reliable detection.

Step 2: Finding Your Device’s MAC Address

If you’re not sure how to find your Bluetooth MAC address, here’s a quick trick - use a BLE scanner app on your phone first. I recommend nRF Connect for Android or LightBlue for iOS. These apps will show you exactly what your device is broadcasting.

Once you have the MAC address, replace the placeholder in the configuration above.

Step 3: Flashing and Testing

Upload the configuration to your ESP32 through ESPHome. After it reboots, check the logs in ESPHome to make sure it’s connecting to WiFi and starting the BLE scanner.

You should see messages like:

[BLEScanner]: Starting BLE scan...
[BLEScanner]: Found device AA:BB:CC:DD:EE:FF RSSI=-65

If you don’t see your device, try moving closer to the ESP32 or checking that your device’s Bluetooth is actually enabled (I’ve wasted hours troubleshooting only to realize Bluetooth was off!).

Step 4: Home Assistant Integration

Now for the magic - getting this data into Home Assistant. Thanks to ESPHome’s seamless integration, your sensors should automatically appear in Home Assistant shortly after the ESP32 connects.

Go to your Home Assistant Overview, click Edit, and add the entities. You should see:

  • binary_sensor.phone_presence
  • sensor.phone_ble_rssi
  • binary_sensor.phone_nearby

Step 5: Creating Presence-Based Automations

Here’s where the fun begins! Let’s create some automations that respond to your presence.

Basic room presence automation:

alias: "Living Room Lights - Auto On"
description: "Turn on lights when entering living room"
trigger:
  - platform: state
    entity_id: binary_sensor.living_room_phone_presence
    to: "on"
condition:
  - condition: state
    entity_id: binary_sensor.living_room_phone_nearby
    state: "on"
  - condition: sun
    after: sunset
    before: sunrise
action:
  - service: light.turn_on
    target:
      entity_id: light.living_room_lights
    data:
      brightness_pct: 70
mode: single

Multi-room tracking setup:

For whole-home presence detection, place ESP32 scanners in key locations (living room, bedroom, office). Then create a template sensor to track your location:

# In configuration.yaml
template:
  - sensor:
      - name: "User Location"
        state: >
          {% if states('binary_sensor.living_room_phone_nearby') == 'on' %}
            Living Room
          {% elif states('binary_sensor.bedroom_phone_nearby') == 'on' %}
            Bedroom
          {% elif states('binary_sensor.office_phone_nearby') == 'on' %}
            Office
          {% else %}
            Away
          {% endif %}          

Advanced Configuration: Filtering and Optimization

After running my BLE scanners for a few weeks, I noticed some issues with false triggers and devices that would “disappear” randomly. Here’s my refined configuration that handles these edge cases:

# Advanced BLE configuration
ble_presence:
  scan_parameters:
    interval: 300ms
    window: 250ms
    active: false

binary_sensor:
  - platform: ble_presence
    mac_address: "AA:BB:CC:DD:EE:FF"
    name: "Phone Presence"
    id: phone_presence
    device_class: presence
    filters:
      - delayed_off: 2min # Wait 2 minutes before marking as away
      - heartbeat: 15min # Force update every 15 minutes to handle edge cases

sensor:
  - platform: ble_rssi
    mac_address: "AA:BB:CC:DD:EE:FF"
    name: "Phone RSSI"
    id: phone_rssi
    update_interval: 30s
    filters:
      - delta: 3.0
      - throttle: 10s
      - exponential_moving_average:
          alpha: 0.1
          send_every: 5
Why this works better: The exponential moving average filter smooths out RSSI fluctuations, while the heartbeat and delayed_off filters prevent false "away" states when your device temporarily stops broadcasting.

Troubleshooting Common Issues

Problem: My device isn’t being detected Solution: Check that your device’s Bluetooth is on and not in power-saving mode. Some devices stop broadcasting BLE when asleep.

Problem: Inconsistent detection Solution: Adjust the RSSI thresholds in the template sensor. -70dBm is typically within 1-2 meters, -85dBm within 5-7 meters.

Problem: ESP32 keeps disconnecting from WiFi Solution: Add a signal_strength sensor and consider moving your ESP32 closer to your router or adding a WiFi repeater.

Problem: Too many unknown devices cluttering the logs Solution: Add the following to your configuration to ignore unknown devices:

ble_scanner:
  scan_parameters:
    interval: 300ms
    window: 250ms
    active: false
  filters:
    - mac_address: "AA:BB:CC:DD:EE:FF" # Only track your device

Taking It Further

Once you have basic presence detection working, here are some ideas to enhance your setup:

  1. Multiple family members: Add MAC addresses for each family member’s devices and create person entities in Home Assistant.

  2. Room-specific automations: “If my phone is detected in the bedroom after 10 PM, set thermostat to night mode.”

  3. Device battery monitoring: Some BLE devices broadcast battery level - you can track this too!

  4. iBeacon/Tag support: Get dedicated BLE tags for items that don’t have built-in Bluetooth like your keys or wallet.

  5. Proximity-based media control: “Pause music when I leave the room, resume when I return.”

Frequently Asked Questions

Q: Will this work with iPhones? A: Yes, but iPhones use randomized MAC addresses by default for privacy. You’ll need to disable this feature for the specific network or use a dedicated BLE tag.

Q: How many devices can one ESP32 track? A: Technically, hundreds. Practically, I’ve successfully tracked up to 15 devices simultaneously without issues.

Q: Does this drain my phone’s battery? A: Negligibly. BLE is designed to be extremely power-efficient, using far less battery than WiFi-based tracking solutions.

Q: Can I use this outdoors? A: Bluetooth range is typically 10-30 meters depending on obstacles. For larger areas, you might need multiple ESP32s or consider GPS tracking.

Q: How accurate is the room detection? A: With proper RSSI calibration, I’ve achieved 95%+ accuracy for room-level detection. Signal strength can be affected by walls, furniture, and even human bodies, so some tuning may be needed.

I’ve been using this setup for months now, and it’s incredibly reliable once properly configured. The best part is watching your home respond to your movements like magic - lights turning on as you approach, music following you from room to room, and the thermostat adjusting based on where everyone actually is in the house.

If you run into any issues or have questions, feel free to reach out on Twitter or check out my other Home Assistant tutorials.

Happy automating!