Switch to bleak for reliable BLE scanning with RSSI
- Replace hcitool-based BT scanning with bleak Python library - Bleak provides reliable RSSI values via D-Bus/BlueZ - BLE scan now finds devices that hcitool missed - Update project docs to reflect resolved BT RSSI blocker - Add bleak>=0.21.0 to dependencies Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,8 +59,8 @@ Understanding the RF environment around you is useful for:
|
|||||||
┌─────────────────────────┴───────────────────────────────────┐
|
┌─────────────────────────┴───────────────────────────────────┐
|
||||||
│ System Tools │
|
│ System Tools │
|
||||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
│ │ iw │ │ hcitool │ │bluetoothctl│ │
|
│ │ iw │ │ bleak │ │ SQLite │ │
|
||||||
│ │ (WiFi) │ │ (BT) │ │ (BLE) │ │
|
│ │ (WiFi) │ │ (BLE) │ │(History) │ │
|
||||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||||
└─────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
@@ -78,6 +78,7 @@ Understanding the RF environment around you is useful for:
|
|||||||
- Flask - Web framework
|
- Flask - Web framework
|
||||||
- PyYAML - Configuration
|
- PyYAML - Configuration
|
||||||
- dataclasses - Data structures
|
- dataclasses - Data structures
|
||||||
|
- bleak - BLE scanning with RSSI
|
||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
- Leaflet.js - 2D maps
|
- Leaflet.js - 2D maps
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
- [x] Live BT tracking mode
|
- [x] Live BT tracking mode
|
||||||
- [x] Moving device detection (purple markers)
|
- [x] Moving device detection (purple markers)
|
||||||
- [x] Filter-aware scanning (WiFi/BT toggle)
|
- [x] Filter-aware scanning (WiFi/BT toggle)
|
||||||
- [ ] Reliable RSSI acquisition for movement tracking
|
- [x] Reliable RSSI acquisition for movement tracking (bleak)
|
||||||
- [ ] Position smoothing/averaging
|
- [ ] Position smoothing/averaging
|
||||||
- [ ] Device trails/history visualization
|
- [ ] Device trails/history visualization
|
||||||
|
|
||||||
|
|||||||
24
TASKS.md
24
TASKS.md
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
| Status | Task | Notes |
|
| Status | Task | Notes |
|
||||||
|--------|------|-------|
|
|--------|------|-------|
|
||||||
| [-] | Fix Bluetooth RSSI acquisition | `hcitool rssi` only works for connected devices; `bluetoothctl` doesn't expose RSSI for cached devices |
|
| [x] | Fix Bluetooth RSSI acquisition | Switched to `bleak` Python library for reliable BLE scanning with RSSI |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
| [x] | Live BT tracking mode | 4-second scan interval |
|
| [x] | Live BT tracking mode | 4-second scan interval |
|
||||||
| [x] | Moving device detection | Purple markers for RSSI changes |
|
| [x] | Moving device detection | Purple markers for RSSI changes |
|
||||||
| [x] | Filter-aware scanning | Skip WiFi/BT based on toggle |
|
| [x] | Filter-aware scanning | Skip WiFi/BT based on toggle |
|
||||||
| [~] | Improve BT discovery reliability | Try alternative scanning methods |
|
| [x] | Improve BT discovery reliability | Using bleak library for BLE scanning |
|
||||||
| [ ] | Document API endpoints | docs/API.md |
|
| [ ] | Document API endpoints | docs/API.md |
|
||||||
| [ ] | Create CHEATSHEET.md | Quick reference guide |
|
| [ ] | Create CHEATSHEET.md | Quick reference guide |
|
||||||
|
|
||||||
@@ -78,28 +78,28 @@
|
|||||||
| Live tracking button | 2026-01-31 |
|
| Live tracking button | 2026-01-31 |
|
||||||
| Purple moving indicators | 2026-01-31 |
|
| Purple moving indicators | 2026-01-31 |
|
||||||
| Smart scanning (filter-aware) | 2026-01-31 |
|
| Smart scanning (filter-aware) | 2026-01-31 |
|
||||||
|
| SQLite historical database | 2026-02-01 |
|
||||||
|
| Bleak BLE scanning (reliable RSSI) | 2026-02-01 |
|
||||||
|
| Auto-start live BT tracking | 2026-02-01 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Blockers
|
## Blockers
|
||||||
|
|
||||||
### BT RSSI Acquisition
|
*No current blockers*
|
||||||
|
|
||||||
|
### ~~BT RSSI Acquisition~~ (RESOLVED)
|
||||||
**Problem:** Cannot get reliable RSSI values for Bluetooth devices
|
**Problem:** Cannot get reliable RSSI values for Bluetooth devices
|
||||||
- `hcitool rssi <addr>` - Only works for connected devices
|
- `hcitool rssi <addr>` - Only works for connected devices
|
||||||
- `bluetoothctl info` - No RSSI for cached devices
|
- `bluetoothctl info` - No RSSI for cached devices
|
||||||
- `btmgmt find` - Not providing output
|
|
||||||
- BLE scan (`hcitool lescan`) - I/O errors on this adapter
|
|
||||||
|
|
||||||
**Potential Solutions:**
|
**Solution:** Switched to `bleak` Python BLE library which provides reliable RSSI via D-Bus/BlueZ.
|
||||||
1. Use D-Bus BlueZ API directly (needs dbus-python)
|
|
||||||
2. Keep devices paired/connected for RSSI polling
|
|
||||||
3. Focus on WiFi-based tracking instead
|
|
||||||
4. Use dedicated BLE beacon hardware
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Bluetooth scanning is unreliable on Raspberry Pi 5 with built-in adapter
|
- BLE scanning now uses `bleak` Python library (reliable RSSI via D-Bus)
|
||||||
- WiFi scanning works well with `iw` command
|
- WiFi scanning works well with `iw` command
|
||||||
- Consider external USB Bluetooth adapter for better BLE support
|
- Live BT tracking auto-starts on page load (3-second scan interval)
|
||||||
|
- Historical data stored in SQLite database with auto-cleanup
|
||||||
|
|||||||
1
TODO.md
1
TODO.md
@@ -214,6 +214,7 @@
|
|||||||
- [x] Device labeling and favorites
|
- [x] Device labeling and favorites
|
||||||
- [x] New device alerts
|
- [x] New device alerts
|
||||||
- [x] Automatic data retention/cleanup
|
- [x] Automatic data retention/cleanup
|
||||||
|
- [x] Reliable BLE scanning with bleak library
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ classifiers = [
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"flask>=3.0.0",
|
"flask>=3.0.0",
|
||||||
"pyyaml>=6.0",
|
"pyyaml>=6.0",
|
||||||
|
"bleak>=0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|||||||
@@ -814,61 +814,32 @@ def create_app(config: Config | None = None) -> Flask:
|
|||||||
|
|
||||||
@app.route("/api/scan/bt", methods=["POST"])
|
@app.route("/api/scan/bt", methods=["POST"])
|
||||||
def api_scan_bt():
|
def api_scan_bt():
|
||||||
"""Quick Bluetooth-only scan for real-time tracking using hcitool"""
|
"""Quick Bluetooth-only scan for real-time tracking using bleak (BLE)"""
|
||||||
import subprocess
|
import asyncio
|
||||||
import re
|
from bleak import BleakScanner
|
||||||
|
|
||||||
bt = []
|
bt = []
|
||||||
try:
|
try:
|
||||||
# Use hcitool inq for classic BT (more reliable)
|
async def do_scan():
|
||||||
result = subprocess.run(
|
devices = await BleakScanner.discover(timeout=3.0, return_adv=True)
|
||||||
['sudo', 'hcitool', 'inq', '--flush'],
|
results = []
|
||||||
capture_output=True,
|
for addr, (device, adv) in devices.items():
|
||||||
text=True,
|
rssi = adv.rssi if adv else -70
|
||||||
timeout=12
|
name = device.name or '<unknown>'
|
||||||
)
|
results.append({
|
||||||
|
|
||||||
for line in result.stdout.split('\n'):
|
|
||||||
# Parse: " E0:03:6B:FE:24:A1 clock offset: 0x15c7 class: 0x08043c"
|
|
||||||
m = re.match(r'\s*([0-9A-Fa-f:]+)\s+clock offset.*class:\s*0x([0-9A-Fa-f]+)', line)
|
|
||||||
if m:
|
|
||||||
addr = m.group(1)
|
|
||||||
device_class = m.group(2)
|
|
||||||
|
|
||||||
# Get device name
|
|
||||||
name = '<unknown>'
|
|
||||||
try:
|
|
||||||
name_result = subprocess.run(
|
|
||||||
['sudo', 'hcitool', 'name', addr],
|
|
||||||
capture_output=True, text=True, timeout=5
|
|
||||||
)
|
|
||||||
if name_result.stdout.strip():
|
|
||||||
name = name_result.stdout.strip()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Get RSSI (only works if device is connectable)
|
|
||||||
rssi = -70 # Default
|
|
||||||
try:
|
|
||||||
rssi_result = subprocess.run(
|
|
||||||
['sudo', 'hcitool', 'rssi', addr],
|
|
||||||
capture_output=True, text=True, timeout=3
|
|
||||||
)
|
|
||||||
rssi_match = re.search(r'RSSI return value:\s*(-?\d+)', rssi_result.stdout)
|
|
||||||
if rssi_match:
|
|
||||||
rssi = int(rssi_match.group(1))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
bt.append({
|
|
||||||
'address': addr,
|
'address': addr,
|
||||||
'name': name,
|
'name': name,
|
||||||
'rssi': rssi,
|
'rssi': rssi,
|
||||||
'device_class': device_class
|
'device_class': 'BLE'
|
||||||
})
|
})
|
||||||
|
return results
|
||||||
|
|
||||||
|
# Run async scan in sync context
|
||||||
|
bt = asyncio.run(do_scan())
|
||||||
|
print(f"[BT] Bleak scan found {len(bt)} devices")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[BT] hcitool scan error: {e}")
|
print(f"[BT] Bleak scan error: {e}")
|
||||||
bt = []
|
bt = []
|
||||||
|
|
||||||
# The scanner already does auto-identification if enabled
|
# The scanner already does auto-identification if enabled
|
||||||
|
|||||||
Reference in New Issue
Block a user