Browse Source

Add comprehensive API documentation for MyBeacon device

Created detailed API documentation covering:
- Device API (local HTTP API on device)
- Server API (backend endpoints)
- All request/response formats
- Authentication and security
- Data flow and examples
- Troubleshooting guide

Documentation includes:
- 10 Device API endpoints
- 5 Server API endpoints
- BLE and WiFi event formats
- WebSocket real-time updates
- Configuration management
- Error codes and examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
root 1 month ago
parent
commit
0e366c44e8
1 changed files with 975 additions and 0 deletions
  1. 975 0
      API_DOCUMENTATION.md

+ 975 - 0
API_DOCUMENTATION.md

@@ -0,0 +1,975 @@
+# MyBeacon API Documentation
+
+## Overview
+
+MyBeacon device provides two types of APIs:
+1. **Device API** - HTTP API running on the device (port 80)
+2. **Server API** - Backend endpoints that device communicates with
+
+**Device Identification:**
+- `device_id`: eth0 MAC address (e.g., `38:54:39:4b:1b:ad`)
+- `device_token`: Authentication token (received during registration)
+- `device_password`: 8-digit PIN for dashboard access
+
+---
+
+## Table of Contents
+
+- [Device API](#device-api) - Running on device
+  - [GET /api/status](#get-apistatus)
+  - [GET /api/metrics](#get-apimetrics)
+  - [GET /api/config](#get-apiconfig)
+  - [GET /api/ble/recent](#get-apiblerecent)
+  - [GET /api/wifi/recent](#get-apiwifirecent)
+  - [GET /api/logs](#get-apilogs)
+  - [GET /api/kernel-logs](#get-apikernel-logs)
+  - [POST /api/unlock](#post-apiunlock)
+  - [POST /api/settings](#post-apisettings)
+  - [WebSocket /api/ws](#websocket-apiws)
+- [Server API](#server-api) - Backend endpoints
+  - [POST /api/v1/registration](#post-apiv1registration)
+  - [GET /api/v1/config](#get-apiv1config)
+  - [POST /api/v1/ble](#post-apiv1ble)
+  - [POST /api/v1/wifi](#post-apiv1wifi)
+  - [POST /api/v1/wifi-credentials](#post-apiv1wifi-credentials)
+
+---
+
+## Device API
+
+Base URL: `http://<device-ip>` (default port 80)
+
+All responses include CORS headers:
+```
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Methods: GET, POST, OPTIONS
+Access-Control-Allow-Headers: Content-Type, Authorization
+```
+
+### GET /api/status
+
+Returns current device status including network state, scanners status, and counters.
+
+**Request:**
+```http
+GET /api/status HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+{
+  "device_id": "38:54:39:4b:1b:ad",
+  "registered": true,
+  "mode": "cloud",
+  "uptime_sec": 45652,
+  "network": {
+    "eth0_ip": "192.168.5.244/24",
+    "eth0_mac": "38:54:39:4b:1b:ad",
+    "eth0_rx": 29226155,
+    "eth0_tx": 53569343,
+    "wlan0_ip": "192.168.5.100/24",
+    "wlan0_mac": "38:54:39:4b:1b:ac",
+    "wlan0_ssid": "MyNetwork",
+    "wlan0_signal": -45,
+    "wlan0_channel": 6,
+    "wlan0_gateway": "192.168.5.1",
+    "wlan0_dns": "192.168.5.1",
+    "wlan0_rx": 1234567,
+    "wlan0_tx": 7654321,
+    "gateway": "192.168.5.1",
+    "dns": "192.168.5.1",
+    "ntp": "pool.ntp.org",
+    "ap_active": false
+  },
+  "scanners": {
+    "ble_running": true,
+    "wifi_running": false
+  },
+  "counters": {
+    "ble_events": 12345,
+    "wifi_events": 6789,
+    "uploads": 42,
+    "errors": 0
+  },
+  "server_ok": true
+}
+```
+
+**Fields:**
+- `device_id`: Device MAC address (eth0)
+- `registered`: Whether device is registered on server
+- `mode`: Operating mode (`cloud` or `lan`)
+- `uptime_sec`: System uptime in seconds
+- `network.eth0_*`: Ethernet interface stats
+- `network.wlan0_*`: WiFi interface stats (only when connected)
+- `network.ap_active`: Whether AP fallback is active
+- `scanners.*_running`: Scanner status
+- `counters`: Event and upload counters
+- `server_ok`: Server connection status
+
+---
+
+### GET /api/metrics
+
+Returns system metrics (CPU, memory, temperature, load).
+
+**Request:**
+```http
+GET /api/metrics HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+{
+  "cpu_percent": 15.5,
+  "mem_used_mb": 42.3,
+  "mem_total_mb": 245.0,
+  "temperature": 45.2,
+  "load_avg": 0.42,
+  "load_1m": 0.42,
+  "load_5m": 0.35,
+  "load_15m": 0.28
+}
+```
+
+**Fields:**
+- `cpu_percent`: CPU usage percentage
+- `mem_used_mb`: Used memory in MB
+- `mem_total_mb`: Total memory in MB
+- `temperature`: SoC temperature in °C
+- `load_avg`: 1-minute load average
+- `load_1m/5m/15m`: Load averages
+
+---
+
+### GET /api/config
+
+Returns current device configuration (without secrets).
+
+**Request:**
+```http
+GET /api/config HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+{
+  "mode": "cloud",
+  "api_base": "http://server:8000/api/v1",
+  "ble": {
+    "enabled": true,
+    "batch_interval_ms": 2500
+  },
+  "wifi": {
+    "monitor_enabled": true,
+    "client_enabled": false,
+    "ssid": "",
+    "batch_interval_ms": 10000
+  },
+  "network": {
+    "ntp_servers": ["pool.ntp.org"],
+    "eth0": {
+      "static": false,
+      "address": "",
+      "gateway": "",
+      "dns": ""
+    }
+  },
+  "dashboard": {
+    "enabled": true
+  },
+  "ssh_tunnel": {
+    "enabled": false,
+    "server": "",
+    "port": 22,
+    "user": "tunnel",
+    "remote_port": 0
+  }
+}
+```
+
+**Note:** Sensitive fields (passwords, keys) are omitted from response.
+
+---
+
+### GET /api/ble/recent
+
+Returns recent BLE events (last 100, kept for 15 seconds).
+
+**Request:**
+```http
+GET /api/ble/recent HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+[
+  {
+    "type": "ibeacon",
+    "mac": "AA:BB:CC:DD:EE:FF",
+    "rssi": -65,
+    "ts_ms": 1703001234567,
+    "uuid": "f7826da64fa24e988024bc5b71e0893e",
+    "major": 100,
+    "minor": 1,
+    "tx_power": -59
+  },
+  {
+    "type": "my-beacon_acc",
+    "mac": "11:22:33:44:55:66",
+    "rssi": -72,
+    "ts_ms": 1703001234568,
+    "x": 123,
+    "y": -45,
+    "z": 678,
+    "bat": 95,
+    "temp": 25.5
+  }
+]
+```
+
+**BLE Event Types:**
+- `ibeacon`: Apple iBeacon format
+- `my-beacon_acc`: Custom accelerometer beacon
+- `rt_mybeacon`: Relay beacon
+
+---
+
+### GET /api/wifi/recent
+
+Returns recent WiFi probe requests (last 100).
+
+**Request:**
+```http
+GET /api/wifi/recent HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+[
+  {
+    "mac": "AA:BB:CC:DD:EE:FF",
+    "rssi": -55,
+    "ts_ms": 1703001234567,
+    "ssid": "MyNetwork",
+    "freq": 2437,
+    "channel": 6
+  }
+]
+```
+
+---
+
+### GET /api/logs
+
+Returns recent daemon log lines (last 500).
+
+**Request:**
+```http
+GET /api/logs HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+[
+  "12:36:28 [ble] Uploaded 2 events to server",
+  "12:36:31 [ble] Uploaded 1 events to server",
+  "12:36:33 [scanner] BLE scanner started (pid=1234)"
+]
+```
+
+---
+
+### GET /api/kernel-logs
+
+Returns kernel log messages from `dmesg` (last 500 lines).
+
+**Request:**
+```http
+GET /api/kernel-logs HTTP/1.1
+Host: 192.168.5.244
+```
+
+**Response:** `200 OK`
+```json
+[
+  "[45666.294334] aicwf_sdio mmc1:7a8a:1 wlan0: CLOSE",
+  "[45666.295543] ieee80211 phy0: HT supp 1, VHT supp 1, HE supp 1"
+]
+```
+
+**Note:** BusyBox dmesg doesn't support `-T` flag, timestamps are in `[seconds.microseconds]` format since boot.
+
+---
+
+### POST /api/unlock
+
+Validates device password and creates a session.
+
+**Request:**
+```http
+POST /api/unlock HTTP/1.1
+Host: 192.168.5.244
+Content-Type: application/json
+
+{
+  "password": "82680499"
+}
+```
+
+**Response:** `200 OK`
+```json
+{
+  "token": "abc123def456..."
+}
+```
+
+**Error Response:** `401 Unauthorized`
+```
+Invalid password
+```
+
+---
+
+### POST /api/settings
+
+Updates device settings (requires valid password).
+
+**Request:**
+```http
+POST /api/settings HTTP/1.1
+Host: 192.168.5.244
+Content-Type: application/json
+
+{
+  "password": "82680499",
+  "settings": {
+    "mode": "cloud",
+    "wifi_client_enabled": true,
+    "wifi_ssid": "MyNetwork",
+    "wifi_psk": "password123",
+    "wifi_monitor_enabled": false,
+    "eth0_mode": "dhcp",
+    "ntp_servers": "pool.ntp.org,time.google.com"
+  }
+}
+```
+
+**Settings Fields:**
+- `mode`: `"cloud"` or `"lan"`
+- `wifi_client_enabled`: Enable WiFi client
+- `wifi_ssid`: WiFi network name
+- `wifi_psk`: WiFi password
+- `wifi_monitor_enabled`: Enable WiFi scanner (LAN mode only)
+- `eth0_mode`: `"dhcp"` or `"static"`
+- `eth0_ip`: Static IP (when `eth0_mode="static"`)
+- `eth0_gateway`: Gateway (static mode)
+- `eth0_dns`: DNS server (static mode)
+- `ntp_servers`: Comma-separated NTP servers
+- `ble_enabled`: Enable BLE scanner (LAN mode only)
+- `ble_batch_interval_ms`: BLE batch interval
+- `wifi_monitor_batch_interval_ms`: WiFi batch interval
+
+**Response:** `200 OK`
+```json
+{
+  "success": true
+}
+```
+
+**Error Response:** `401 Unauthorized`
+```
+Invalid password
+```
+
+**Note:**
+- In Cloud mode, scanner settings come from server
+- In LAN mode, scanner settings are local
+- WiFi client settings work in both modes
+- Changes to WiFi credentials in Cloud mode are also sent to server
+
+---
+
+### WebSocket /api/ws
+
+Real-time event stream for dashboard updates.
+
+**Connection:**
+```javascript
+const ws = new WebSocket('ws://192.168.5.244/api/ws');
+```
+
+**Message Format:**
+```json
+{
+  "type": "ble",
+  "event": {
+    "mac": "AA:BB:CC:DD:EE:FF",
+    "rssi": -65,
+    "ts_ms": 1703001234567
+  }
+}
+```
+
+**Message Types:**
+- `type: "ble"`: BLE event
+- `type: "wifi"`: WiFi event
+- `type: "log"`: Log message
+
+---
+
+## Server API
+
+Base URL: Configured in device settings (default: `http://server:8000/api/v1`)
+
+Authentication: Bearer token in `Authorization` header (except registration).
+
+### POST /api/v1/registration
+
+Registers a new device with the server. Called once on first boot.
+
+**Request:**
+```http
+POST /api/v1/registration HTTP/1.1
+Host: server:8000
+Content-Type: application/json
+
+{
+  "device_id": "38:54:39:4b:1b:ad",
+  "eth_ip": "192.168.5.244",
+  "wlan_ip": "192.168.5.100",
+  "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
+}
+```
+
+**Fields:**
+- `device_id`: Device MAC address (eth0)
+- `eth_ip`: Ethernet IP address (optional)
+- `wlan_ip`: WiFi IP address (optional)
+- `ssh_public_key`: SSH public key for tunnel (optional)
+
+**Response:** `201 Created`
+```json
+{
+  "device_token": "gRMRUKnqO9KXikBzoKhs0aE3uDYUvTxHYuU4/uatyrc=",
+  "device_password": "82680499",
+  "ssh_tunnel": {
+    "enabled": true,
+    "remote_port": 50123,
+    "server": "tunnel.example.com"
+  }
+}
+```
+
+**Response Fields:**
+- `device_token`: Authentication token for API calls (save to `/opt/mybeacon/etc/device.json`)
+- `device_password`: 8-digit PIN for dashboard (save to device.json)
+- `ssh_tunnel`: SSH tunnel configuration (optional)
+
+**Error Response:** `400 Bad Request`
+```json
+{
+  "error": "device_id is required"
+}
+```
+
+---
+
+### GET /api/v1/config
+
+Fetches device configuration from server (Cloud mode only, polled every 30 seconds).
+
+**Request:**
+```http
+GET /api/v1/config?device_id=38:54:39:4b:1b:ad HTTP/1.1
+Host: server:8000
+Authorization: Bearer gRMRUKnqO9KXikBzoKhs0aE3uDYUvTxHYuU4/uatyrc=
+```
+
+**Response:** `200 OK`
+```json
+{
+  "force_cloud": false,
+  "ble": {
+    "enabled": true,
+    "batch_interval_ms": 2500,
+    "uuid_filter_hex": ""
+  },
+  "wifi": {
+    "client_enabled": false,
+    "ssid": "",
+    "psk": "",
+    "monitor_enabled": true,
+    "batch_interval_ms": 10000
+  },
+  "ssh_tunnel": {
+    "enabled": true,
+    "server": "tunnel.example.com",
+    "port": 22,
+    "user": "tunnel",
+    "remote_port": 50123,
+    "keepalive_interval": 30
+  },
+  "dashboard_tunnel": {
+    "enabled": true,
+    "server": "tunnel.example.com",
+    "port": 22,
+    "user": "tunnel",
+    "remote_port": 60123,
+    "keepalive_interval": 30
+  },
+  "dashboard": {
+    "enabled": true
+  },
+  "net": {
+    "ntp": {
+      "servers": ["pool.ntp.org", "time.google.com"]
+    }
+  },
+  "debug": false
+}
+```
+
+**Configuration Priority:**
+- **Cloud mode:** Server settings override local for BLE, WiFi, NTP
+- **LAN mode:** Local settings have priority
+- **Always from server:** SSH tunnel, Dashboard tunnel, Dashboard enable/disable
+- **Always local:** eth0 network settings
+
+**Error Response:** `401 Unauthorized`
+```
+Invalid or missing token
+```
+
+---
+
+### POST /api/v1/ble
+
+Uploads batch of BLE events (gzip compressed).
+
+**Request:**
+```http
+POST /api/v1/ble HTTP/1.1
+Host: server:8000
+Authorization: Bearer gRMRUKnqO9KXikBzoKhs0aE3uDYUvTxHYuU4/uatyrc=
+Content-Type: application/json
+Content-Encoding: gzip
+
+<gzipped JSON payload>
+```
+
+**Uncompressed Payload:**
+```json
+{
+  "device_id": "38:54:39:4b:1b:ad",
+  "events": [
+    {
+      "type": "ibeacon",
+      "mac": "AA:BB:CC:DD:EE:FF",
+      "rssi": -65,
+      "ts_ms": 1703001234567,
+      "uuid": "f7826da64fa24e988024bc5b71e0893e",
+      "major": 100,
+      "minor": 1,
+      "tx_power": -59
+    },
+    {
+      "type": "my-beacon_acc",
+      "mac": "11:22:33:44:55:66",
+      "rssi": -72,
+      "ts_ms": 1703001234568,
+      "x": 123,
+      "y": -45,
+      "z": 678,
+      "bat": 95,
+      "temp": 25.5,
+      "ff": false
+    }
+  ]
+}
+```
+
+**Event Types and Fields:**
+
+**iBeacon:**
+- `type`: `"ibeacon"`
+- `mac`: Device MAC address
+- `rssi`: Signal strength (dBm)
+- `ts_ms`: Timestamp (milliseconds since epoch)
+- `uuid`: iBeacon UUID (32 hex chars, no dashes)
+- `major`: Major value (0-65535)
+- `minor`: Minor value (0-65535)
+- `tx_power`: Calibrated TX power
+
+**my-beacon_acc:**
+- `type`: `"my-beacon_acc"`
+- `mac`: Device MAC address
+- `rssi`: Signal strength (dBm)
+- `ts_ms`: Timestamp
+- `x`, `y`, `z`: Accelerometer values
+- `bat`: Battery level (0-100)
+- `temp`: Temperature (°C)
+- `ff`: Free fall detected (boolean)
+
+**rt_mybeacon (Relay):**
+- `type`: `"rt_mybeacon"`
+- `mac`: Relay device MAC
+- `rssi`: Signal strength at relay
+- `ts_ms`: Timestamp
+- `relay_mac`: Original beacon MAC
+- `relay_rssi`: Original RSSI
+
+**Response:** `200 OK`
+
+**Error Response:** `401 Unauthorized` / `500 Internal Server Error`
+
+**Notes:**
+- Device retries up to 3 times on failure
+- Failed batches are spooled to `/var/spool/mybeacon/ble/` (max 100MB)
+- Batching interval: 2.5 seconds (default)
+- Average batch size: 5-12 events
+
+---
+
+### POST /api/v1/wifi
+
+Uploads batch of WiFi probe requests (gzip compressed).
+
+**Request:**
+```http
+POST /api/v1/wifi HTTP/1.1
+Host: server:8000
+Authorization: Bearer gRMRUKnqO9KXikBzoKhs0aE3uDYUvTxHYuU4/uatyrc=
+Content-Type: application/json
+Content-Encoding: gzip
+
+<gzipped JSON payload>
+```
+
+**Uncompressed Payload:**
+```json
+{
+  "device_id": "38:54:39:4b:1b:ad",
+  "events": [
+    {
+      "mac": "AA:BB:CC:DD:EE:FF",
+      "rssi": -55,
+      "ts_ms": 1703001234567,
+      "ssid": "MyNetwork",
+      "freq": 2437,
+      "channel": 6
+    }
+  ]
+}
+```
+
+**Event Fields:**
+- `mac`: Device MAC address
+- `rssi`: Signal strength (dBm)
+- `ts_ms`: Timestamp (milliseconds since epoch)
+- `ssid`: Network SSID (may be empty for probe requests)
+- `freq`: Frequency (MHz)
+- `channel`: WiFi channel
+
+**Response:** `200 OK`
+
+**Notes:**
+- Batching interval: 10 seconds (default)
+- Average batch size: 10-200 events
+- Spool directory: `/var/spool/mybeacon/wifi/`
+
+---
+
+### POST /api/v1/wifi-credentials
+
+Updates WiFi client credentials (Cloud mode only).
+
+**Request:**
+```http
+POST /api/v1/wifi-credentials HTTP/1.1
+Host: server:8000
+Authorization: Bearer gRMRUKnqO9KXikBzoKhs0aE3uDYUvTxHYuU4/uatyrc=
+Content-Type: application/json
+
+{
+  "ssid": "NewNetwork",
+  "psk": "password123"
+}
+```
+
+**Response:** `200 OK`
+```json
+{
+  "success": true
+}
+```
+
+**Purpose:**
+When user changes WiFi credentials via dashboard in Cloud mode, device:
+1. Saves credentials locally
+2. Connects to new network
+3. Sends credentials to server for centralized management
+
+Server can use this for:
+- Displaying current WiFi config in user dashboard
+- Remote WiFi management via config endpoint
+- Syncing settings across devices
+
+---
+
+## Error Codes
+
+**Device API:**
+- `200 OK`: Success
+- `401 Unauthorized`: Invalid password
+- `405 Method Not Allowed`: Wrong HTTP method
+- `500 Internal Server Error`: Server error
+
+**Server API:**
+- `200 OK`: Success
+- `201 Created`: Resource created
+- `400 Bad Request`: Invalid request
+- `401 Unauthorized`: Invalid/missing token
+- `500 Internal Server Error`: Server error
+
+---
+
+## Data Flow
+
+### Device Startup
+1. Device boots, reads `/opt/mybeacon/etc/device.json`
+2. If `device_token` missing → POST `/api/v1/registration`
+3. Save token and password to `device.json`
+4. Start polling GET `/api/v1/config` every 30s (Cloud mode)
+
+### Event Upload
+1. BLE/WiFi scanner publishes to ZMQ
+2. Daemon batches events (2.5s for BLE, 10s for WiFi)
+3. Gzip compress → POST `/api/v1/ble` or `/api/v1/wifi`
+4. On failure → spool to disk, retry later
+
+### Configuration Management
+1. **Cloud mode:** Server config overrides local (via `/api/v1/config`)
+2. **LAN mode:** Local config used, no polling
+3. User changes via dashboard → POST `/api/settings` → apply locally
+4. In Cloud mode, WiFi credentials also sent to server
+
+---
+
+## Authentication
+
+**Server API:**
+- Uses Bearer token authentication
+- Token received during registration
+- Include in header: `Authorization: Bearer <token>`
+
+**Device API:**
+- Most endpoints are open (read-only)
+- Write endpoints require `device_password`
+- Password is 8-digit number generated during registration
+
+---
+
+## Network Modes
+
+### Cloud Mode (Default)
+- Config polled from server every 30s
+- BLE/WiFi scanner settings from server
+- Local changes to scanners ignored
+- WiFi client credentials sync with server
+- SSH/Dashboard tunnels controlled by server
+
+### LAN Mode
+- No config polling
+- All settings local
+- Manual configuration via dashboard
+- No server dependency (except registration)
+
+**Switching Modes:**
+Via dashboard → Settings → Mode → Apply
+
+**Force Cloud:**
+Server can set `force_cloud: true` in config to prevent mode switching (for support).
+
+---
+
+## Files
+
+**Configuration:**
+- `/opt/mybeacon/etc/config.json` - Local config
+- `/opt/mybeacon/etc/device.json` - Device state (token, password)
+- `/opt/mybeacon/etc/tunnel_key` - SSH private key
+
+**Logs:**
+- `/var/log/mybeacon.log` - Daemon logs (tmpfs)
+- Kernel logs via `dmesg`
+
+**Spool:**
+- `/var/spool/mybeacon/ble/` - Failed BLE batches
+- `/var/spool/mybeacon/wifi/` - Failed WiFi batches
+- Max total: 100MB
+
+---
+
+## Examples
+
+### Registering a New Device
+
+```bash
+curl -X POST http://server:8000/api/v1/registration \
+  -H "Content-Type: application/json" \
+  -d '{
+    "device_id": "38:54:39:4b:1b:ad",
+    "eth_ip": "192.168.5.244"
+  }'
+```
+
+### Fetching Device Status
+
+```bash
+curl http://192.168.5.244/api/status | jq
+```
+
+### Changing WiFi Settings
+
+```bash
+curl -X POST http://192.168.5.244/api/settings \
+  -H "Content-Type: application/json" \
+  -d '{
+    "password": "82680499",
+    "settings": {
+      "wifi_client_enabled": true,
+      "wifi_ssid": "MyNetwork",
+      "wifi_psk": "password123"
+    }
+  }'
+```
+
+### Uploading BLE Events (with gzip)
+
+```bash
+# Prepare JSON
+echo '{
+  "device_id": "38:54:39:4b:1b:ad",
+  "events": [{"type":"ibeacon","mac":"AA:BB:CC:DD:EE:FF","rssi":-65,"ts_ms":1703001234567}]
+}' | gzip > /tmp/events.json.gz
+
+# Upload
+curl -X POST http://server:8000/api/v1/ble \
+  -H "Authorization: Bearer YOUR_TOKEN" \
+  -H "Content-Type: application/json" \
+  -H "Content-Encoding: gzip" \
+  --data-binary @/tmp/events.json.gz
+```
+
+### WebSocket Example (JavaScript)
+
+```javascript
+const ws = new WebSocket('ws://192.168.5.244/api/ws');
+
+ws.onmessage = (event) => {
+  const msg = JSON.parse(event.data);
+
+  if (msg.type === 'ble') {
+    console.log('BLE event:', msg.event);
+  } else if (msg.type === 'wifi') {
+    console.log('WiFi event:', msg.event);
+  } else if (msg.type === 'log') {
+    console.log('Log:', msg.message);
+  }
+};
+
+ws.onopen = () => console.log('Connected');
+ws.onerror = (err) => console.error('Error:', err);
+```
+
+---
+
+## Security Notes
+
+1. **Device Password:** 8-digit numeric PIN, generated during registration
+2. **Device Token:** Base64-encoded random token, store securely
+3. **HTTPS:** Not implemented on device (use VPN/tunnel for remote access)
+4. **SSH Tunnel:** Ed25519 key-based authentication
+5. **CORS:** Enabled on device API (allow all origins)
+
+---
+
+## Troubleshooting
+
+### Device not uploading events
+1. Check `GET /api/status` → `server_ok: true`
+2. Check logs: `GET /api/logs`
+3. Verify network: `GET /api/status` → `network`
+4. Check spool directory: `ls -lh /var/spool/mybeacon/`
+
+### WiFi scanner not working
+1. Check if WiFi client active: `GET /api/status` → `network.wlan0_ip`
+2. WiFi client and scanner can't run simultaneously
+3. Disable client or use AP mode
+4. Check AIC8800 chip conflicts in logs
+
+### Configuration not applying
+1. Cloud mode: Wait for next poll (30s) or restart daemon
+2. LAN mode: Check password and permissions
+3. Verify mode: `GET /api/config` → `mode`
+
+---
+
+## Appendix: BLE Event Formats
+
+### iBeacon Format
+```
+Company ID: 0x004C (Apple)
+Type: 0x02 0x15
+UUID: 16 bytes
+Major: 2 bytes (big-endian)
+Minor: 2 bytes (big-endian)
+TX Power: 1 byte (signed)
+```
+
+### my-beacon_acc Format
+```
+Company ID: 0x0059 (Nordic)
+Prefix: "acc" (3 bytes)
+X: 2 bytes (signed)
+Y: 2 bytes (signed)
+Z: 2 bytes (signed)
+Battery: 1 byte (0-100)
+Temp: 1 byte (signed, °C)
+Free Fall: 1 bit
+```
+
+### rt_mybeacon Format
+```
+Company ID: 0xFFFF (Custom)
+Prefix: "rt" (2 bytes)
+Original MAC: 6 bytes
+Original RSSI: 1 byte (signed)
+Original payload: variable
+```
+
+---
+
+## Version
+
+**API Version:** 1.0
+**Last Updated:** 2025-12-28
+**Device Firmware:** Alpine Linux + MyBeacon Native
+**Compatible with:** Backend API v1
+
+---
+
+## Support
+
+For issues or questions:
+- Check device logs: `GET /api/logs`
+- Check kernel logs: `GET /api/kernel-logs`
+- SSH to device: `ssh root@<device-ip>` (password: `1`)
+- Review daemon status: `/etc/init.d/S98mybeacon status`