# RTL_433 API Endpoints - Documentation ## Overview The GigLez API now includes RTL_433 integration endpoints for device identification and protocol information. **Base URL:** `http://localhost:8000` (development) **API Version:** 1.0.0 --- ## New Endpoints ### 1. GET `/api/rtl433/status` **Description:** Check RTL_433 decoder availability and status **Response:** ```json { "available": true, "version": "rtl_433 version 23.11 (2023-11-28) inputs file rtl_tcp RTL-SDR SoapySDR", "binary_path": "rtl_433", "timeout": 10, "status": "operational" } ``` **Status Codes:** - `200 OK` - Request successful - `500 Internal Server Error` - Server error **Example:** ```bash curl http://localhost:8000/api/rtl433/status ``` --- ### 2. GET `/api/rtl433/protocols` **Description:** Get list of all supported RTL_433 protocols **Response:** ```json { "total": 244, "protocols": [ { "id": 1, "name": "Silvercrest Remote Control" }, { "id": 2, "name": "Rubicson, TFA 30.3197 or InFactory PT-310 Temperature Sensor" }, ... ] } ``` **Status Codes:** - `200 OK` - Request successful - `503 Service Unavailable` - RTL_433 not available **Example:** ```bash curl http://localhost:8000/api/rtl433/protocols ``` **Filter Protocols (client-side):** ```bash # Get only weather sensor protocols curl -s http://localhost:8000/api/rtl433/protocols | \ jq '.protocols[] | select(.name | contains("Weather") or contains("Temperature"))' ``` --- ### 3. GET `/rtl433/protocols/{protocol_id}` **Description:** Get information about a specific protocol **Path Parameters:** - `protocol_id` (integer) - Protocol ID number (1-244) **Response:** ```json { "id": 12, "name": "Oregon Scientific Weather Sensor" } ``` **Status Codes:** - `200 OK` - Protocol found - `404 Not Found` - Protocol ID doesn't exist - `503 Service Unavailable` - RTL_433 not available **Example:** ```bash curl http://localhost:8000/rtl433/protocols/12 ``` --- ### 4. POST `/api/v1/captures/upload` (Updated) **Description:** Upload .sub files for processing (now includes RTL_433 decoding) **Request:** - `files`: List of .sub files - `manifest`: JSON metadata **Updated Response:** ```json { "success": true, "message": "Processed 1 files successfully", "successful": [ { "id": 1, "filename": "capture.sub", "frequency": 433920000, "protocol": "RAW", "device_name": "Acurite Temperature Sensor", "match_confidence": 0.95, "match_method": "rtl433_decode", // NEW: RTL_433 decoded devices "rtl433_decoded": [ { "model": "Acurite Tower Sensor", "manufacturer": "Acurite", "device_id": "12345", "protocol_id": 40, "confidence": 0.95 } ], // NEW: Combined matches (signature + RTL_433) "matched_devices": [ { "device_name": "Acurite Tower Sensor", "category": "RTL_433 Decoded", "confidence": 0.95, "method": "rtl433_decode", "description": "Acurite Acurite Tower Sensor (Protocol 40)" }, { "device_name": "Weather Station", "category": "Weather Sensor", "confidence": 0.75, "method": "frequency_match", "description": "Generic 433MHz weather sensor" } ] } ], "failed": [], "total_uploaded": 1, "total_successful": 1, "total_failed": 0 } ``` **New Fields:** - `rtl433_decoded[]` - Array of devices decoded by RTL_433 - `matched_devices[]` - Combined matches from all matchers (RTL_433 + signature matching) --- ## Testing the API ### Quick Test Script ```bash #!/bin/bash echo "Testing RTL_433 API Endpoints" echo "==============================" # Test 1: Status echo -e "\n1. Testing /api/rtl433/status" curl -s http://localhost:8000/api/rtl433/status | jq . # Test 2: Protocol count echo -e "\n2. Testing /api/rtl433/protocols (count)" curl -s http://localhost:8000/api/rtl433/protocols | jq '{total: .total}' # Test 3: First 5 protocols echo -e "\n3. First 5 protocols:" curl -s http://localhost:8000/api/rtl433/protocols | jq '.protocols[:5]' # Test 4: Specific protocol echo -e "\n4. Protocol 40 (Acurite):" curl -s http://localhost:8000/rtl433/protocols/40 | jq . echo -e "\nAll tests complete!" ``` **Save as:** `tests/test_rtl433_api.sh` **Run:** ```bash chmod +x tests/test_rtl433_api.sh ./tests/test_rtl433_api.sh ``` --- ## Python Client Examples ### Example 1: Check RTL_433 Status ```python import requests response = requests.get('http://localhost:8000/api/rtl433/status') data = response.json() if data['available']: print(f"RTL_433 is operational") print(f"Version: {data['version']}") else: print("RTL_433 is not available") ``` ### Example 2: Get All Weather Sensor Protocols ```python import requests response = requests.get('http://localhost:8000/api/rtl433/protocols') protocols = response.json()['protocols'] weather_protocols = [ p for p in protocols if 'weather' in p['name'].lower() or 'temperature' in p['name'].lower() or 'sensor' in p['name'].lower() ] print(f"Found {len(weather_protocols)} weather-related protocols:") for p in weather_protocols[:10]: print(f" [{p['id']:3d}] {p['name']}") ``` ### Example 3: Upload File with RTL_433 Decoding ```python import requests import json # Prepare manifest manifest = { "captures": [{ "latitude": 34.0478, "longitude": -118.2348, "timestamp": "2026-01-14T12:00:00Z" }], "data_source": "test" } # Upload file files = {'files': open('capture.sub', 'rb')} data = {'manifest': json.dumps(manifest)} response = requests.post( 'http://localhost:8000/api/v1/captures/upload', files=files, data=data ) result = response.json() if result['success']: for capture in result['successful']: print(f"File: {capture['filename']}") # Check RTL_433 results if capture.get('rtl433_decoded'): print(f" RTL_433 Decoded:") for device in capture['rtl433_decoded']: print(f" - {device['manufacturer']} {device['model']}") print(f" Protocol: {device['protocol_id']}") print(f" Confidence: {device['confidence']}") else: print(" No RTL_433 decode") # Check signature matches if capture.get('matched_devices'): print(f" All Matches ({len(capture['matched_devices'])}):") for match in capture['matched_devices'][:3]: print(f" - {match['device_name']} ({match['confidence']})") ``` --- ## API Documentation Interactive API documentation is available at: - **Swagger UI:** http://localhost:8000/docs - **ReDoc:** http://localhost:8000/redoc Both provide: - Interactive endpoint testing - Request/response schemas - Example requests - Authentication details --- ## Response Format Standards ### Success Response ```json { "success": true, "data": { ... }, "message": "Optional success message" } ``` ### Error Response ```json { "success": false, "error": "Error description", "detail": "Detailed error message" } ``` ### RTL_433 Unavailable ```json { "available": false, "status": "unavailable", "error": "RTL_433 binary not found" } ``` --- ## Rate Limiting Currently no rate limiting is implemented. **Recommended limits for production:** - `/api/rtl433/status` - 60 requests/minute - `/api/rtl433/protocols` - 10 requests/minute - `/api/v1/captures/upload` - 100 uploads/hour --- ## Common Use Cases ### 1. Check if RTL_433 is Available Before Upload ```javascript async function uploadWithRTL433() { // Check RTL_433 status first const status = await fetch('/api/rtl433/status').then(r => r.json()); if (!status.available) { console.warn('RTL_433 not available, falling back to signature matching'); } // Proceed with upload const formData = new FormData(); formData.append('files', file); formData.append('manifest', JSON.stringify(manifest)); const result = await fetch('/api/v1/captures/upload', { method: 'POST', body: formData }).then(r => r.json()); return result; } ``` ### 2. Display RTL_433 Protocols in UI ```javascript async function loadProtocols() { const data = await fetch('/api/rtl433/protocols').then(r => r.json()); const select = document.getElementById('protocol-select'); data.protocols.forEach(protocol => { const option = document.createElement('option'); option.value = protocol.id; option.textContent = `[${protocol.id}] ${protocol.name}`; select.appendChild(option); }); } ``` ### 3. Show RTL_433 Results in Capture Details ```javascript function displayCapture(capture) { const container = document.getElementById('capture-details'); // Show RTL_433 decoded devices if (capture.rtl433_decoded && capture.rtl433_decoded.length > 0) { const rtlSection = document.createElement('div'); rtlSection.className = 'rtl433-results'; rtlSection.innerHTML = `

RTL_433 Decoded (High Confidence)

${capture.rtl433_decoded.map(d => `
${d.manufacturer} ${d.model} ${(d.confidence * 100).toFixed(0)}% Protocol ${d.protocol_id}
`).join('')} `; container.appendChild(rtlSection); } // Show all matches if (capture.matched_devices && capture.matched_devices.length > 0) { const matchSection = document.createElement('div'); matchSection.innerHTML = `

All Matches

${capture.matched_devices.map(m => `
${m.device_name} ${m.method} ${(m.confidence * 100).toFixed(0)}%
`).join('')} `; container.appendChild(matchSection); } } ``` --- ## Troubleshooting ### RTL_433 Status Returns "unavailable" **Problem:** `/api/rtl433/status` shows `"available": false` **Solutions:** 1. Install RTL_433: ```bash sudo apt-get install rtl-433 ``` 2. Verify installation: ```bash rtl_433 -V ``` 3. Check PATH: ```bash which rtl_433 ``` ### Protocols Endpoint Returns Empty **Problem:** `/api/rtl433/protocols` returns `"total": 0` **Cause:** RTL_433 binary not accessible **Solution:** Restart API server after installing RTL_433 ### Upload Returns No RTL_433 Decodes **Problem:** `rtl433_decoded` is always empty **Possible Causes:** 1. Signal too short/noisy for RTL_433 2. Protocol not supported 3. RAW data missing from .sub file **Check:** - Verify .sub file has `RAW_Data` field - Try with known working captures (weather sensors) - Check decoder logs for errors --- ## Performance Notes ### RTL_433 Decode Time - Average: 0.01-0.05 seconds per file - Timeout: 10 seconds - Subprocess overhead: ~10-50ms ### Caching (Future) Phase 7 will add caching to reduce repeated decodes: - Cache key: SHA256 of RAW_Data - TTL: 15 minutes - Expected speedup: 90%+ for duplicates --- ## Security Considerations ### Input Validation - File size limits: 1MB per .sub file - File type validation: Must be valid .sub format - GPS coordinate validation: -90 to 90 lat, -180 to 180 lon ### Subprocess Safety - RTL_433 runs in isolated subprocess - 10 second timeout prevents hangs - Temp files cleaned up automatically - No user input passed to shell ### Rate Limiting (TODO) Production deployment should implement: - Per-IP rate limiting - API key authentication - Upload quotas --- ## Changelog ### Version 1.0.0 (2026-01-14) **Added:** - `GET /api/rtl433/status` - Check RTL_433 availability - `GET /api/rtl433/protocols` - List supported protocols - `GET /rtl433/protocols/{id}` - Get specific protocol info - RTL_433 decoding in `/api/v1/captures/upload` **Updated:** - Upload response now includes `rtl433_decoded[]` array - Upload response includes combined `matched_devices[]` array - Best match now prioritizes RTL_433 results --- ## Support **Documentation:** - Implementation Plan: `docs/RTL433_INTEGRATION_PLAN.md` - Status Report: `docs/RTL433_IMPLEMENTATION_STATUS.md` **Testing:** - Test Suite: `tests/test_rtl433_integration.py` - API Tests: `tests/test_rtl433_api.sh` **Code:** - Converter: `src/parser/rtl433_converter.py` - Decoder: `src/matcher/rtl433_decoder.py` - Strategies: `src/matcher/strategies.py` - API Routes: `src/api/routes/hardware.py`, `src/api/main_simple.py`