Files
rf-mapper/docs/HOME_ASSISTANT.md
User 91536860ad docs: update CLI commands to use python -m rf_mapper
- Replace rf-mapper with python -m rf_mapper throughout docs
- Add note about activating venv first
- Updated: CLAUDE.md, PROJECT.md, USAGE.md, CHEATSHEET.md, HOME_ASSISTANT.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 17:38:44 +01:00

11 KiB

Home Assistant Integration

RF Mapper integrates with Home Assistant using webhooks. RF Mapper sends events to HA, and HA automations handle the logic.

Features

Feature Description HA Entity Type
Device presence Track WiFi/BT devices device_tracker.rf_*
New device alerts Notify on unknown device automation trigger
Departure alerts Notify when device leaves automation trigger
Sensor entities Device count, nearest distance sensor.rf_*
Multi-scanner Room-level presence detection per-scanner sensors

Architecture

Single Scanner

RF Mapper                          Home Assistant
------------------------------------------------------
[Scan] ----webhook----> /api/webhook/rf_mapper_scan
                        |-- automation: update sensors
                        |-- automation: device_tracker.see

[New Device] --webhook--> /api/webhook/rf_mapper_new_device
                          |-- automation: notify

[Device Gone] --webhook-> /api/webhook/rf_mapper_device_gone
                          |-- automation: notify

Multi-Scanner Setup

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Pi #1       │     │ Pi #2       │     │ Pi #3       │
│ scanner:    │     │ scanner:    │     │ scanner:    │
│   id: living│     │   id: kitchen│    │   id: bedroom│
│   floor: 0  │     │   floor: 0  │     │   floor: 1  │
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
       │                   │                   │
       └───────────────────┼───────────────────┘
                           ▼
                   ┌───────────────┐
                   │ Home Assistant │
                   │ - Track nearest│
                   │   scanner/device│
                   │ - Room presence │
                   └───────────────┘

RF Mapper Configuration

Enable webhooks in config.yaml:

# Scanner identity (for multi-scanner support)
scanner:
  id: "living_room"           # Unique scanner ID
  name: "Living Room Scanner" # Human-readable name
  latitude: 50.8584           # Scanner position (optional, falls back to gps.latitude)
  longitude: 4.3976           # Scanner position (optional, falls back to gps.longitude)
  floor: 0                    # Scanner's floor (optional, falls back to building.current_floor)

home_assistant:
  enabled: true
  url: "http://192.168.129.10:8123"
  webhook_scan: "rf_mapper_scan"
  webhook_new_device: "rf_mapper_new_device"
  webhook_device_gone: "rf_mapper_device_gone"
  device_timeout_minutes: 5

Scanner Identity Settings

Setting Description
scanner.id Unique scanner identifier (auto-generated from hostname if empty)
scanner.name Human-readable display name (defaults to id)
scanner.latitude Scanner latitude (falls back to gps.latitude)
scanner.longitude Scanner longitude (falls back to gps.longitude)
scanner.floor Scanner's floor number (falls back to building.current_floor)

Home Assistant Settings

Setting Description
enabled Enable/disable HA integration
url Home Assistant URL (no trailing slash)
webhook_scan Webhook ID for scan results
webhook_new_device Webhook ID for new device alerts
webhook_device_gone Webhook ID for departure alerts
device_timeout_minutes Minutes before device is considered departed

Home Assistant Setup

1. Automations (automations.yaml)

# Process scan results - update device trackers with scanner info
- alias: "RF Mapper - Update Device Trackers"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_scan
  action:
    - repeat:
        for_each: "{{ trigger.json.devices }}"
        sequence:
          - service: device_tracker.see
            data:
              dev_id: "rf_{{ repeat.item.id | replace(':', '_') }}"
              source_type: "{{ 'bluetooth' if ':' in repeat.item.id else 'router' }}"
              attributes:
                friendly_name: "{{ repeat.item.name }}"
                rssi: "{{ repeat.item.rssi }}"
                distance_m: "{{ repeat.item.distance }}"
                floor: "{{ repeat.item.floor }}"
                scanner_id: "{{ trigger.json.scanner.id }}"
                scanner_name: "{{ trigger.json.scanner.name }}"

# New device notification (includes which scanner detected it)
- alias: "RF Mapper - New Device Alert"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_new_device
  action:
    - service: notify.persistent_notification
      data:
        title: "New Device Detected"
        message: >
          {{ trigger.json.device_type }}: {{ trigger.json.name }}
          ({{ trigger.json.device_id }})
          detected by {{ trigger.json.scanner.name | default('unknown scanner') }}

# Device departure notification (includes last scanner)
- alias: "RF Mapper - Device Left"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_device_gone
  action:
    - service: notify.persistent_notification
      data:
        title: "Device Left"
        message: >
          {{ trigger.json.name }} last seen {{ trigger.json.last_seen }}
          at {{ trigger.json.last_scanner.name | default('unknown location') }}

2. Sensor Templates (configuration.yaml)

template:
  - trigger:
      - platform: webhook
        webhook_id: rf_mapper_scan
    sensor:
      # Per-scanner device count sensor
      - name: "RF Scanner {{ trigger.json.scanner.id }} Device Count"
        unique_id: "rf_scanner_{{ trigger.json.scanner.id }}_count"
        state: "{{ trigger.json.device_count }}"
        icon: mdi:bluetooth
        attributes:
          scanner_id: "{{ trigger.json.scanner.id }}"
          scanner_name: "{{ trigger.json.scanner.name }}"
          scanner_floor: "{{ trigger.json.scanner.floor }}"

      # Per-scanner nearest device sensor
      - name: "RF Scanner {{ trigger.json.scanner.id }} Nearest"
        unique_id: "rf_scanner_{{ trigger.json.scanner.id }}_nearest"
        state: "{{ trigger.json.devices | map(attribute='distance') | min | round(1) if trigger.json.devices else 'none' }}"
        unit_of_measurement: "m"
        icon: mdi:map-marker-distance
        attributes:
          scanner_id: "{{ trigger.json.scanner.id }}"

Webhook Payload Reference

Scan Results (rf_mapper_scan)

{
  "timestamp": "2026-02-01T12:34:56.789",
  "scan_type": "bluetooth",
  "scanner": {
    "id": "living_room",
    "name": "Living Room Scanner",
    "latitude": 50.8584,
    "longitude": 4.3976,
    "floor": 0
  },
  "scanner_floor": 0,
  "device_count": 5,
  "devices": [
    {
      "id": "AA:BB:CC:DD:EE:FF",
      "name": "iPhone",
      "rssi": -65,
      "distance": 3.2,
      "floor": 0
    }
  ]
}
Field Description
scanner Full scanner identity object
scanner.id Unique scanner identifier
scanner.name Human-readable scanner name
scanner.latitude Scanner GPS latitude
scanner.longitude Scanner GPS longitude
scanner.floor Floor where scanner is located
scanner_floor (Deprecated) Same as scanner.floor, for backward compatibility

New Device (rf_mapper_new_device)

{
  "timestamp": "2026-02-01T12:34:56.789",
  "device_id": "AA:BB:CC:DD:EE:FF",
  "name": "Unknown Device",
  "device_type": "bluetooth",
  "manufacturer": "Apple, Inc.",
  "rssi": -70,
  "distance_m": 5.5,
  "scanner": {
    "id": "living_room",
    "name": "Living Room Scanner",
    "latitude": 50.8584,
    "longitude": 4.3976,
    "floor": 0
  }
}

Device Gone (rf_mapper_device_gone)

{
  "timestamp": "2026-02-01T12:34:56.789",
  "device_id": "AA:BB:CC:DD:EE:FF",
  "name": "iPhone",
  "device_type": "bluetooth",
  "last_seen": "2026-02-01T12:29:00.000",
  "last_scanner": {
    "id": "living_room",
    "name": "Living Room Scanner",
    "latitude": 50.8584,
    "longitude": 4.3976,
    "floor": 0
  }
}

Verification Steps

  1. Enable integration: Set home_assistant.enabled: true in config.yaml
  2. Add HA automations: Copy webhook automations to HA
  3. Restart RF Mapper: source venv/bin/activate && python -m rf_mapper restart
  4. Run scan: Trigger BT scan in RF Mapper web UI
  5. Check HA: Verify device_tracker.rf_* entities appear
  6. Test new device: Clear device from DB, re-scan, verify notification
  7. Test departure: Wait for timeout, verify departure notification
  8. Check sensors: Verify sensor.rf_mapper_* values update

Troubleshooting

Issue Solution
Webhooks not received Check HA URL in config, ensure no firewall blocking
No device trackers Verify automation is enabled in HA
Departure not triggered Increase device_timeout_minutes
Connection timeout Check network connectivity between RF Mapper and HA

Multi-Scanner Setup

Configure each scanner with a unique ID and position:

Pi #1 (Living Room):

scanner:
  id: "living_room"
  name: "Living Room Scanner"
  floor: 0
  latitude: 50.8584
  longitude: 4.3976

Pi #2 (Kitchen):

scanner:
  id: "kitchen"
  name: "Kitchen Scanner"
  floor: 0
  latitude: 50.8585
  longitude: 4.3978

Pi #3 (Bedroom):

scanner:
  id: "bedroom"
  name: "Bedroom Scanner"
  floor: 1
  latitude: 50.8584
  longitude: 4.3977

Room Presence Automation

# Track which room a device is in (nearest scanner)
- alias: "RF Mapper - Track Room Presence"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_scan
  action:
    - repeat:
        for_each: "{{ trigger.json.devices }}"
        sequence:
          - service: input_text.set_value
            target:
              entity_id: "input_text.rf_{{ repeat.item.id | replace(':', '_') }}_room"
            data:
              value: "{{ trigger.json.scanner.id }}"

Advanced: Presence-based Automations

# Turn on lights when specific device arrives in living room
- alias: "Welcome Home - Living Room"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_scan
  condition:
    - condition: template
      value_template: >
        {{ trigger.json.scanner.id == 'living_room' and
           trigger.json.devices | selectattr('id', 'eq', 'AA:BB:CC:DD:EE:FF') | list | count > 0 }}
  action:
    - service: light.turn_on
      target:
        entity_id: light.living_room

# Turn off lights when device leaves a room
- alias: "Room Empty Check"
  trigger:
    - platform: webhook
      webhook_id: rf_mapper_scan
  condition:
    - condition: template
      value_template: "{{ trigger.json.scanner.id == 'bedroom' and trigger.json.device_count == 0 }}"
  action:
    - service: light.turn_off
      target:
        entity_id: light.bedroom