feat: add Home Assistant integration and improve CLI/UI
Home Assistant Integration: - New homeassistant.py module with webhook support - Webhooks for scan results, new devices, and device departures - Absence detection with configurable timeout - Documentation in docs/HOME_ASSISTANT.md CLI Improvements: - Replace 'web' command with start/stop/restart/status - Background daemon mode with PID file management - Foreground mode for debugging (--foreground) Web UI Enhancements: - Improved device list styling and layout - Better floor assignment UI - Enhanced map visualization Documentation: - Add CHANGELOG.md - Add docs/API.md with full endpoint reference - Add docs/CHEATSHEET.md for quick reference - Update project documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
750
docs/API.md
Normal file
750
docs/API.md
Normal file
@@ -0,0 +1,750 @@
|
||||
# RF Mapper API Reference
|
||||
|
||||
REST API documentation for RF Mapper web interface.
|
||||
|
||||
**Base URL:** `http://localhost:5000`
|
||||
|
||||
---
|
||||
|
||||
## Scanning
|
||||
|
||||
### Trigger Scan
|
||||
|
||||
Performs WiFi and/or Bluetooth scan.
|
||||
|
||||
```
|
||||
POST /api/scan
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `location` | string | `"web_scan"` | Location label for the scan |
|
||||
| `lat` | number | config value | GPS latitude |
|
||||
| `lon` | number | config value | GPS longitude |
|
||||
| `scan_wifi` | boolean | `true` | Include WiFi networks |
|
||||
| `scan_bluetooth` | boolean | `true` | Include Bluetooth devices |
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/scan \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"location": "kitchen", "scan_wifi": true, "scan_bluetooth": true}'
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-02-01T14:30:00.123456",
|
||||
"location": "kitchen",
|
||||
"gps": {"lat": 50.8585, "lon": 4.3978},
|
||||
"wifi_networks": [
|
||||
{
|
||||
"ssid": "HomeNetwork",
|
||||
"bssid": "AA:BB:CC:DD:EE:FF",
|
||||
"rssi": -45,
|
||||
"channel": 6,
|
||||
"frequency": 2437,
|
||||
"encryption": "WPA2",
|
||||
"manufacturer": "Cisco",
|
||||
"estimated_distance_m": 3.5,
|
||||
"signal_quality": "Excellent",
|
||||
"floor": null,
|
||||
"height_m": null
|
||||
}
|
||||
],
|
||||
"bluetooth_devices": [
|
||||
{
|
||||
"address": "11:22:33:44:55:66",
|
||||
"name": "iPhone",
|
||||
"rssi": -60,
|
||||
"device_class": "Phone",
|
||||
"device_type": "Smartphone",
|
||||
"manufacturer": "Apple",
|
||||
"estimated_distance_m": 5.2,
|
||||
"signal_quality": "Good",
|
||||
"floor": null,
|
||||
"height_m": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Quick Bluetooth Scan
|
||||
|
||||
Fast BLE-only scan for real-time tracking (uses bleak library).
|
||||
|
||||
```
|
||||
POST /api/scan/bt
|
||||
```
|
||||
|
||||
**Response:** Same as `/api/scan` but only `bluetooth_devices` populated.
|
||||
|
||||
---
|
||||
|
||||
### Get Latest Scan
|
||||
|
||||
Retrieve the most recent scan results.
|
||||
|
||||
```
|
||||
GET /api/latest
|
||||
```
|
||||
|
||||
**Response:** Same format as `/api/scan` response.
|
||||
|
||||
---
|
||||
|
||||
### List Scans
|
||||
|
||||
List saved scan files (most recent 50).
|
||||
|
||||
```
|
||||
GET /api/scans
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"filename": "scan_20260201_143000_kitchen.json",
|
||||
"timestamp": "2026-02-01T14:30:00",
|
||||
"location": "kitchen",
|
||||
"wifi_count": 12,
|
||||
"bt_count": 5
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Specific Scan
|
||||
|
||||
Retrieve a specific scan by filename.
|
||||
|
||||
```
|
||||
GET /api/scans/<filename>
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:5000/api/scans/scan_20260201_143000_kitchen.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Position & Configuration
|
||||
|
||||
### GPS Position
|
||||
|
||||
Get or set current GPS position.
|
||||
|
||||
```
|
||||
GET /api/position
|
||||
POST /api/position
|
||||
```
|
||||
|
||||
**POST Body:**
|
||||
|
||||
```json
|
||||
{"lat": 50.8585, "lon": 4.3978}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{"lat": 50.8585, "lon": 4.3978}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Configuration
|
||||
|
||||
Get or update application configuration.
|
||||
|
||||
```
|
||||
GET /api/config
|
||||
POST /api/config
|
||||
```
|
||||
|
||||
**POST Body:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `gps.latitude` | number | GPS latitude |
|
||||
| `gps.longitude` | number | GPS longitude |
|
||||
| `scanner.path_loss_exponent` | number | Distance calculation parameter |
|
||||
| `save` | boolean | Persist changes to config file |
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/config \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"gps": {"latitude": 50.85, "longitude": 4.39}, "save": true}'
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"gps": {"latitude": 50.85, "longitude": 4.39},
|
||||
"web": {"host": "0.0.0.0", "port": 5000},
|
||||
"scanner": {
|
||||
"wifi_interface": "wlan0",
|
||||
"bt_scan_timeout": 10,
|
||||
"path_loss_exponent": 2.5
|
||||
},
|
||||
"config_file": "/home/user/git/rf-mapper/config.yaml"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Building Configuration
|
||||
|
||||
Get or update building configuration for 3D visualization.
|
||||
|
||||
```
|
||||
GET /api/building
|
||||
POST /api/building
|
||||
```
|
||||
|
||||
**POST Body:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `enabled` | boolean | Enable 3D building view |
|
||||
| `name` | string | Building name |
|
||||
| `floors` | integer | Number of floors |
|
||||
| `floor_height_m` | number | Height per floor (meters) |
|
||||
| `ground_floor_number` | integer | Ground floor number (0 or 1) |
|
||||
| `current_floor` | integer | Scanner's current floor |
|
||||
| `save` | boolean | Persist changes |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"name": "Home",
|
||||
"floors": 3,
|
||||
"floor_height_m": 3.0,
|
||||
"ground_floor_number": 0,
|
||||
"current_floor": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Device Management
|
||||
|
||||
### Set Device Floor
|
||||
|
||||
Assign a floor to a device (persists in database).
|
||||
|
||||
```
|
||||
POST /api/device/<device_id>/floor
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `device_id`: BSSID (WiFi) or address (Bluetooth)
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"floor": 2, "height_m": 6.0}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "updated",
|
||||
"device_id": "AA:BB:CC:DD:EE:FF",
|
||||
"device_type": "wifi",
|
||||
"floor": 2,
|
||||
"height_m": 6.0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Set Device Distance
|
||||
|
||||
Override estimated distance for a device.
|
||||
|
||||
```
|
||||
POST /api/device/<device_id>/distance
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"distance": 5.5}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get All Floor Assignments
|
||||
|
||||
Retrieve all saved floor assignments.
|
||||
|
||||
```
|
||||
GET /api/device/floors
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"AA:BB:CC:DD:EE:FF": 2,
|
||||
"11:22:33:44:55:66": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bluetooth Identification
|
||||
|
||||
### Identify Single Device
|
||||
|
||||
Get detailed info about a Bluetooth device.
|
||||
|
||||
```
|
||||
GET /api/bluetooth/identify/<address>
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:5000/api/bluetooth/identify/11:22:33:44:55:66
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Batch Identify
|
||||
|
||||
Identify multiple devices (max 10).
|
||||
|
||||
```
|
||||
POST /api/bluetooth/identify
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"addresses": ["11:22:33:44:55:66", "AA:BB:CC:DD:EE:FF"]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Auto-Scan
|
||||
|
||||
### Get Status
|
||||
|
||||
```
|
||||
GET /api/autoscan
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"running": true,
|
||||
"interval_minutes": 5,
|
||||
"location_label": "auto_scan",
|
||||
"scan_wifi": true,
|
||||
"scan_bluetooth": true,
|
||||
"last_scan_time": "2026-02-01T14:30:00",
|
||||
"last_scan_result": {"timestamp": "...", "wifi_count": 12, "bt_count": 5},
|
||||
"scan_count": 42
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Start Auto-Scan
|
||||
|
||||
```
|
||||
POST /api/autoscan/start
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `interval_minutes` | integer | 5 | Scan interval |
|
||||
| `location_label` | string | `"auto_scan"` | Location label |
|
||||
| `scan_wifi` | boolean | `true` | Include WiFi |
|
||||
| `scan_bluetooth` | boolean | `true` | Include Bluetooth |
|
||||
| `save` | boolean | `false` | Persist to config |
|
||||
|
||||
---
|
||||
|
||||
### Stop Auto-Scan
|
||||
|
||||
```
|
||||
POST /api/autoscan/stop
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"save": true}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Settings
|
||||
|
||||
```
|
||||
POST /api/autoscan/settings
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"interval_minutes": 10, "location_label": "living_room", "save": true}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Historical Data API
|
||||
|
||||
All history endpoints require database to be enabled in config.
|
||||
|
||||
### List Devices
|
||||
|
||||
Get all tracked devices with statistics.
|
||||
|
||||
```
|
||||
GET /api/history/devices
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `type` | string | Filter by `wifi` or `bluetooth` |
|
||||
| `since` | string | ISO timestamp filter |
|
||||
| `limit` | integer | Max results (default: 100) |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"devices": [
|
||||
{
|
||||
"device_id": "AA:BB:CC:DD:EE:FF",
|
||||
"device_type": "wifi",
|
||||
"name": "HomeNetwork",
|
||||
"ssid": "HomeNetwork",
|
||||
"manufacturer": "Cisco",
|
||||
"first_seen": "2026-01-15T10:00:00",
|
||||
"last_seen": "2026-02-01T14:30:00",
|
||||
"total_observations": 500,
|
||||
"custom_label": "Main Router",
|
||||
"is_favorite": 1,
|
||||
"assigned_floor": 1
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Device Details
|
||||
|
||||
```
|
||||
GET /api/history/devices/<device_id>
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"device": { ... },
|
||||
"stats": {
|
||||
"avg_rssi": -55.3,
|
||||
"min_rssi": -75,
|
||||
"max_rssi": -40,
|
||||
"avg_distance_m": 4.2,
|
||||
"min_distance_m": 1.5,
|
||||
"max_distance_m": 12.0,
|
||||
"total_observations": 500
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get RSSI History
|
||||
|
||||
Time series RSSI data for a device.
|
||||
|
||||
```
|
||||
GET /api/history/devices/<device_id>/rssi
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `since` | string | ISO timestamp filter |
|
||||
| `limit` | integer | Max results (default: 1000) |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "AA:BB:CC:DD:EE:FF",
|
||||
"observations": [
|
||||
{"timestamp": "2026-02-01T14:30:00", "rssi": -55, "distance_m": 4.2, "floor": 1}
|
||||
],
|
||||
"count": 100
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Activity Pattern
|
||||
|
||||
Hourly/daily activity pattern for a device.
|
||||
|
||||
```
|
||||
GET /api/history/devices/<device_id>/activity
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `days` | integer | 7 | Analysis period |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "AA:BB:CC:DD:EE:FF",
|
||||
"period_days": 7,
|
||||
"hourly_pattern": {
|
||||
"8": {"count": 50, "avg_rssi": -55.0},
|
||||
"9": {"count": 45, "avg_rssi": -52.3}
|
||||
},
|
||||
"daily_pattern": {
|
||||
"0": 120,
|
||||
"1": 115
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Set Device Label
|
||||
|
||||
```
|
||||
POST /api/history/devices/<device_id>/label
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"label": "Living Room TV"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Toggle Favorite
|
||||
|
||||
```
|
||||
POST /api/history/devices/<device_id>/favorite
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"favorite": true}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Movement Events
|
||||
|
||||
```
|
||||
GET /api/history/movement
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `device_id` | string | Filter by device |
|
||||
| `since` | string | ISO timestamp filter |
|
||||
| `limit` | integer | Max results (default: 100) |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"id": 1,
|
||||
"device_id": "11:22:33:44:55:66",
|
||||
"timestamp": "2026-02-01T14:30:00",
|
||||
"rssi_delta": 10,
|
||||
"distance_delta_m": -2.5,
|
||||
"direction": "approaching",
|
||||
"velocity_m_s": 0.5
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Alerts
|
||||
|
||||
```
|
||||
GET /api/history/alerts
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `acknowledged` | boolean | Filter by acknowledged status |
|
||||
| `type` | string | Filter by type: `new_device`, `device_absent`, `rssi_threshold` |
|
||||
| `limit` | integer | Max results (default: 50) |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"alerts": [
|
||||
{
|
||||
"id": 1,
|
||||
"alert_type": "new_device",
|
||||
"device_id": "11:22:33:44:55:66",
|
||||
"timestamp": "2026-02-01T14:30:00",
|
||||
"message": "New Bluetooth device detected: iPhone (Apple)",
|
||||
"acknowledged": 0
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Acknowledge Alert
|
||||
|
||||
```
|
||||
POST /api/history/alerts/<alert_id>/acknowledge
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Activity Summary
|
||||
|
||||
```
|
||||
GET /api/history/activity
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `hours` | integer | 24 | Period in hours |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"period_hours": 24,
|
||||
"since": "2026-01-31T14:30:00",
|
||||
"active_wifi_devices": 12,
|
||||
"active_bt_devices": 8,
|
||||
"total_observations": 2500,
|
||||
"movement_events": 15,
|
||||
"new_devices": 2,
|
||||
"scan_count": 288
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Database Stats
|
||||
|
||||
```
|
||||
GET /api/history/stats
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"total_devices": 45,
|
||||
"total_observations": 50000,
|
||||
"total_scans": 1200,
|
||||
"total_movement_events": 300,
|
||||
"unread_alerts": 5,
|
||||
"database_size_bytes": 5242880,
|
||||
"database_size_mb": 5.0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Manual Cleanup
|
||||
|
||||
Trigger data cleanup (removes old records).
|
||||
|
||||
```
|
||||
POST /api/history/cleanup
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{"retention_days": 30}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"retention_days": 30,
|
||||
"cutoff": "2026-01-02T14:30:00",
|
||||
"cleaned_at": "2026-02-01T14:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
All endpoints return errors in this format:
|
||||
|
||||
```json
|
||||
{"error": "Error message here"}
|
||||
```
|
||||
|
||||
**Common HTTP Status Codes:**
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 200 | Success |
|
||||
| 400 | Bad request (missing/invalid parameters) |
|
||||
| 404 | Resource not found |
|
||||
| 500 | Internal server error |
|
||||
| 503 | Database not enabled |
|
||||
Reference in New Issue
Block a user