- 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>
485 lines
13 KiB
Markdown
485 lines
13 KiB
Markdown
# RF Mapper Usage Guide
|
|
|
|
RF Mapper is a WiFi and Bluetooth signal mapper for Linux. It scans nearby devices, estimates distances, and visualizes results in multiple views including radar, 2.5D, world map, and 3D map with building support.
|
|
|
|
## Requirements
|
|
|
|
- Linux with WiFi and Bluetooth hardware (or Android via Termux)
|
|
- Python 3.10+
|
|
- `sudo` access (required for scanning on Linux)
|
|
- System tools: `iw`, `hcitool`, `bluetoothctl`
|
|
|
|
### Android/Termux Requirements
|
|
|
|
For running RF Mapper on Android via Termux:
|
|
|
|
| Requirement | Description |
|
|
|-------------|-------------|
|
|
| **Termux** | From F-Droid (NOT Play Store) |
|
|
| **Termux:API** | From F-Droid (same source as Termux) |
|
|
| **Termux:Boot** | Optional, for auto-start on boot |
|
|
| **termux-api package** | `pkg install termux-api` |
|
|
| **Location permission** | Grant to Termux:API app |
|
|
| **GPS enabled** | Enable Location in Android settings |
|
|
|
|
**Important:** All Termux apps must be from the same source (F-Droid recommended). Mixing Play Store and F-Droid versions causes API communication failures.
|
|
|
|
#### ADB Configuration for Android 12+
|
|
|
|
Android 12+ has a "phantom process killer" that terminates background processes. Disable it for stable Termux operation:
|
|
|
|
```bash
|
|
# Connect via ADB and run:
|
|
adb shell "settings put global settings_enable_monitor_phantom_procs false"
|
|
```
|
|
|
|
This setting persists across reboots but may reset after Android updates.
|
|
|
|
#### Verify Termux Prerequisites
|
|
|
|
```bash
|
|
# Check if all prerequisites are met
|
|
rf-mapper check-termux
|
|
```
|
|
|
|
Output shows status of each requirement:
|
|
```
|
|
==================================================
|
|
TERMUX ENVIRONMENT DETECTED
|
|
Checking prerequisites...
|
|
==================================================
|
|
✓ Termux:API package: OK
|
|
✓ Location services: OK (lat: 50.8585)
|
|
✓ Wake lock: OK (wake lock acquired)
|
|
✓ Termux:Boot: OK (boot directory exists)
|
|
==================================================
|
|
All prerequisites met. Starting RF Mapper...
|
|
```
|
|
|
|
#### Termux Boot Script
|
|
|
|
For auto-start on device boot, create `~/.termux/boot/start-rf-mapper.sh`:
|
|
|
|
```bash
|
|
#!/data/data/com.termux/files/usr/bin/bash
|
|
termux-wake-lock
|
|
cd ~/git/rf-mapper
|
|
source venv/bin/activate
|
|
python -m rf_mapper start
|
|
```
|
|
|
|
Make it executable:
|
|
```bash
|
|
chmod +x ~/.termux/boot/start-rf-mapper.sh
|
|
```
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
# Create and activate virtual environment
|
|
python -m venv venv
|
|
source venv/bin/activate
|
|
|
|
# Install dependencies
|
|
pip install -e .
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Activate venv
|
|
source venv/bin/activate
|
|
|
|
# Run interactive scan
|
|
python -m rf_mapper
|
|
|
|
# Start web server
|
|
python -m rf_mapper start
|
|
```
|
|
|
|
## CLI Commands
|
|
|
|
All commands require activating the virtual environment first:
|
|
```bash
|
|
source venv/bin/activate
|
|
```
|
|
|
|
### Scanning
|
|
|
|
```bash
|
|
# Basic scan (interactive mode)
|
|
python -m rf_mapper
|
|
|
|
# Scan with location label
|
|
python -m rf_mapper scan -l kitchen
|
|
|
|
# Scan WiFi only
|
|
python -m rf_mapper scan --no-bt
|
|
|
|
# Scan Bluetooth only
|
|
python -m rf_mapper scan --no-wifi
|
|
|
|
# Use specific WiFi interface
|
|
python -m rf_mapper scan -i wlan1
|
|
```
|
|
|
|
### Visualization (CLI)
|
|
|
|
```bash
|
|
# Visualize latest scan (ASCII radar + charts)
|
|
python -m rf_mapper visualize
|
|
|
|
# Visualize specific scan file
|
|
python -m rf_mapper visualize -f data/scan_20240131_120000_kitchen.json
|
|
|
|
# Analyze RF environment
|
|
python -m rf_mapper analyze
|
|
```
|
|
|
|
### Scan History
|
|
|
|
```bash
|
|
# List saved scans
|
|
python -m rf_mapper list
|
|
```
|
|
|
|
### Web Server
|
|
|
|
```bash
|
|
# Start web server (background daemon)
|
|
python -m rf_mapper start
|
|
|
|
# Start in foreground (for debugging)
|
|
python -m rf_mapper start --foreground
|
|
|
|
# Custom host/port
|
|
python -m rf_mapper start -H 127.0.0.1 -p 8080
|
|
|
|
# With debug mode
|
|
python -m rf_mapper start --foreground --debug
|
|
|
|
# With request profiling
|
|
python -m rf_mapper start --profile-requests
|
|
|
|
# With request logging
|
|
python -m rf_mapper start --log-requests
|
|
|
|
# Stop the server
|
|
python -m rf_mapper stop
|
|
|
|
# Restart the server
|
|
python -m rf_mapper restart
|
|
|
|
# Check server status
|
|
python -m rf_mapper status
|
|
```
|
|
|
|
### Configuration
|
|
|
|
```bash
|
|
# Show current configuration
|
|
python -m rf_mapper config
|
|
|
|
# Set GPS coordinates
|
|
python -m rf_mapper config --set-gps 50.8585 4.3978 --save
|
|
|
|
# Check Termux prerequisites (Android only)
|
|
rf-mapper check-termux
|
|
```
|
|
|
|
### Profiling
|
|
|
|
```bash
|
|
# Profile CPU usage
|
|
rf-mapper --profile scan
|
|
|
|
# Profile memory usage
|
|
rf-mapper --profile-memory scan
|
|
|
|
# Save profile to file
|
|
rf-mapper --profile --profile-output scan.prof scan
|
|
```
|
|
|
|
## Web Interface Views
|
|
|
|
The web dashboard offers 3 visualization modes:
|
|
|
|
| View | Description |
|
|
|------|-------------|
|
|
| **Radar** | Classic radar display with distance rings |
|
|
| **World Map** | Leaflet map with device markers on real geography |
|
|
| **3D Map** | MapLibre GL 3D view with building extrusion |
|
|
|
|
### Features
|
|
|
|
- Real-time scanning via "New Scan" button
|
|
- Auto-scan mode with configurable interval
|
|
- WiFi/Bluetooth filter toggles
|
|
- Floor filtering for multi-story buildings
|
|
- Click devices for detailed info popups
|
|
- Device lists with signal strength indicators
|
|
|
|
## Configuration File
|
|
|
|
Configuration is loaded from (in order):
|
|
1. `./config.yaml`
|
|
2. `~/.config/rf-mapper/config.yaml`
|
|
3. `/etc/rf-mapper/config.yaml`
|
|
|
|
### Example `config.yaml`
|
|
|
|
```yaml
|
|
gps:
|
|
latitude: 50.8585853
|
|
longitude: 4.3978724
|
|
|
|
web:
|
|
host: "0.0.0.0"
|
|
port: 5000
|
|
debug: false
|
|
|
|
scanner:
|
|
wifi_interface: "wlan0"
|
|
bt_scan_timeout: 10
|
|
path_loss_exponent: 2.5
|
|
auto_identify_bluetooth: true
|
|
|
|
data:
|
|
directory: "data"
|
|
max_scans: 100
|
|
|
|
building:
|
|
enabled: false
|
|
name: "My Building"
|
|
floors: 3
|
|
floor_height_m: 3.0
|
|
ground_floor_number: 0
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `RF_MAPPER_LAT` | Override GPS latitude |
|
|
| `RF_MAPPER_LON` | Override GPS longitude |
|
|
| `RF_MAPPER_HOST` | Override web server host |
|
|
| `RF_MAPPER_PORT` | Override web server port |
|
|
| `HA_TOKEN` | Home Assistant API token |
|
|
| `HA_URL` | Home Assistant URL |
|
|
|
|
## API Endpoints
|
|
|
|
The web server exposes a REST API:
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/api/health` | Health check for monitoring |
|
|
| POST | `/api/scan` | Trigger new scan |
|
|
| GET | `/api/latest` | Get most recent scan |
|
|
| GET | `/api/scans` | List all scans |
|
|
| GET | `/api/scans/<filename>` | Get specific scan |
|
|
| GET/POST | `/api/position` | Get/set GPS position |
|
|
| GET/POST | `/api/config` | Get/update configuration |
|
|
| GET/POST | `/api/building` | Get/update building config |
|
|
| POST | `/api/device/<id>/floor` | Assign floor to device |
|
|
| GET | `/api/autoscan` | Get auto-scan status |
|
|
| POST | `/api/autoscan/start` | Start auto-scanning |
|
|
| POST | `/api/autoscan/stop` | Stop auto-scanning |
|
|
| GET | `/api/bluetooth/identify/<addr>` | Identify BT device |
|
|
|
|
## Multi-Node Master Dashboard
|
|
|
|
RF Mapper supports a multi-node architecture where one designated "master" node can view and control scanning on peer nodes without page redirects.
|
|
|
|
### Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Master Node (rpios) │
|
|
│ ┌───────────────────────────────────────────────────┐ │
|
|
│ │ Node Selector: [📍 rpios ▼] │ │
|
|
│ │ ├─ 📍 rpios (local) │ │
|
|
│ │ ├─ 📡 grokbox │ │
|
|
│ │ └─ 📡 jellystar │ │
|
|
│ └───────────────────────────────────────────────────┘ │
|
|
│ │ │ │ │
|
|
│ [Radar] [3D Map] [Device Lists] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
│
|
|
┌────────────────┼────────────────┐
|
|
▼ ▼ ▼
|
|
grokbox:5000 jellystar:5000 (local)
|
|
```
|
|
|
|
### Enabling Master Mode
|
|
|
|
Set `is_master: true` in `config.yaml` on the master node:
|
|
|
|
```yaml
|
|
scanner:
|
|
id: 'rpios'
|
|
name: 'Master Scanner'
|
|
is_master: true # Enable master dashboard features
|
|
peers: [] # Peers auto-register via API
|
|
accept_registrations: true
|
|
```
|
|
|
|
Peer nodes do NOT need this flag (defaults to `false`).
|
|
|
|
### Node Selector
|
|
|
|
When `is_master: true` and peers are registered, a node selector dropdown appears in the header:
|
|
|
|
| Indicator | Meaning |
|
|
|-----------|---------|
|
|
| 📍 | Local scanner (this node) |
|
|
| 📡 | Peer scanner (remote node) |
|
|
| ● (green) | Connected and responding |
|
|
| ● (yellow) | Connecting/loading |
|
|
| ○ (red) | Peer unreachable |
|
|
|
|
### Switching Between Nodes
|
|
|
|
1. Click the node selector dropdown
|
|
2. Select a peer node (e.g., "📡 grokbox")
|
|
3. Dashboard recenters on peer's GPS location
|
|
4. Device lists show peer's scanned devices
|
|
5. WebSocket connects to peer for real-time updates
|
|
|
|
When viewing a peer:
|
|
- Map centers on peer's coordinates
|
|
- Radar shows devices relative to peer
|
|
- "New Scan" triggers scan on peer node
|
|
- Live tracking runs scans on peer
|
|
|
|
### Live Tracking on Remote Nodes
|
|
|
|
Live tracking works across nodes:
|
|
|
|
1. Select a peer from node selector
|
|
2. Enable "Live BT Track" toggle
|
|
3. Scans run on the selected peer (not locally)
|
|
4. Results stream back via WebSocket
|
|
5. Map updates in real-time with peer's devices
|
|
|
|
### Proxy API Endpoints
|
|
|
|
The master node provides proxy endpoints to access peer data:
|
|
|
|
| Endpoint | Description |
|
|
|----------|-------------|
|
|
| `/api/node/<id>/latest` | Get latest scan from peer |
|
|
| `/api/node/<id>/scan/bt` | Trigger BT scan on peer |
|
|
| `/api/node/<id>/device/floors` | Get device floor assignments |
|
|
| `/api/node/<id>/positions/trilaterated` | Get trilaterated positions |
|
|
|
|
Example:
|
|
```bash
|
|
# Get grokbox's latest scan via master
|
|
curl http://rpios:5000/api/node/grokbox/latest | jq
|
|
|
|
# Trigger BT scan on grokbox
|
|
curl -X POST http://rpios:5000/api/node/grokbox/scan/bt
|
|
```
|
|
|
|
### Peer Registration
|
|
|
|
Peers register with the master automatically or manually:
|
|
|
|
```bash
|
|
# Manual registration from peer
|
|
curl -X POST http://rpios:5000/api/peers/register \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id": "grokbox",
|
|
"name": "Grokbox Scanner",
|
|
"url": "http://grokbox:5000",
|
|
"latitude": 50.858495,
|
|
"longitude": 4.397614,
|
|
"floor": 11
|
|
}'
|
|
|
|
# List registered peers
|
|
curl http://rpios:5000/api/peers | jq '.peers'
|
|
```
|
|
|
|
### WebSocket Peer Connections
|
|
|
|
When viewing a peer node, the dashboard:
|
|
|
|
1. Disconnects from local WebSocket
|
|
2. Connects to peer's WebSocket at `peer_url/ws/scan`
|
|
3. Receives real-time scan updates from peer
|
|
4. Falls back to HTTP polling if WebSocket fails
|
|
|
|
## Data Storage
|
|
|
|
Scan results are saved as JSON in the data directory:
|
|
- Default: `./data/`
|
|
- Files: `scan_YYYYMMDD_HHMMSS_<location>.json`
|
|
|
|
## Troubleshooting
|
|
|
|
### "WiFi scan error: Operation not permitted"
|
|
Run with sudo or ensure your user has permissions:
|
|
```bash
|
|
sudo rf-mapper scan
|
|
```
|
|
|
|
### "No Bluetooth adapter found"
|
|
Ensure Bluetooth is enabled:
|
|
```bash
|
|
sudo systemctl start bluetooth
|
|
sudo hciconfig hci0 up
|
|
```
|
|
|
|
### Web interface shows no devices
|
|
1. Run a scan first: click "New Scan" or use CLI
|
|
2. Check if data directory has scan files
|
|
3. Verify filters aren't hiding devices
|
|
|
|
### 3D buildings not showing
|
|
- Zoom in to level 15+ for buildings to appear
|
|
- Not all areas have building data in OpenStreetMap
|
|
- The map style must support vector tiles with building data
|
|
|
|
### Termux: "Termux:API app not responding"
|
|
1. Ensure Termux:API is from F-Droid (not Play Store)
|
|
2. Grant all permissions to Termux:API in Android settings
|
|
3. Restart Termux after installing Termux:API
|
|
|
|
### Termux: Process killed in background
|
|
Android's phantom process killer terminates background processes. Fix:
|
|
```bash
|
|
adb shell "settings put global settings_enable_monitor_phantom_procs false"
|
|
```
|
|
|
|
### Termux: Location services failing
|
|
1. Enable GPS/Location in Android settings
|
|
2. Grant location permission to Termux:API
|
|
3. Test with: `termux-location -p passive`
|
|
4. Ensure you're outdoors or near windows for GPS signal
|
|
|
|
### Termux: Wake lock not working
|
|
1. Disable battery optimization for Termux in Android settings
|
|
2. Run `termux-wake-lock` before starting RF Mapper
|
|
3. The app acquires wake lock automatically on start
|
|
|
|
### Master Dashboard: Node selector not appearing
|
|
1. Verify `is_master: true` in config.yaml
|
|
2. Restart rf-mapper: `python -m rf_mapper restart`
|
|
3. Check peers are registered: `curl http://localhost:5000/api/peers | jq '.peers | length'`
|
|
4. At least one peer must be registered for selector to appear
|
|
|
|
### Master Dashboard: Peer shows red status
|
|
1. Check peer is running: `curl http://peer:5000/api/peers`
|
|
2. Check network connectivity: `ping peer`
|
|
3. Check firewall allows port 5000
|
|
4. Re-register peer if needed (see Peer Registration above)
|
|
|
|
### Master Dashboard: WebSocket to peer fails
|
|
1. Check peer WebSocket endpoint: `curl http://peer:5000/socket.io/`
|
|
2. Browser console shows connection errors
|
|
3. Falls back to HTTP polling automatically
|
|
4. Ensure peer is running with WebSocket support enabled
|