8560fb5002
Implemented full RTL_433 decoder integration for automatic IoT device identification:
## Phase 1-6: Core Implementation
- RTL_433 binary integration (v23.11, 244 protocols)
- Pulse data converter (RAW_Data → am.s16 format)
- Subprocess decoder wrapper with JSON parsing
- RTL433DecoderStrategy for matcher pipeline
- Comprehensive test suite (all tests passing)
## Phase 8: API Integration (this commit)
- GET /api/rtl433/status - Check decoder availability
- GET /api/rtl433/protocols - List 244 supported protocols
- GET /rtl433/protocols/{id} - Get protocol info
- POST /api/v1/captures/upload - Updated with RTL_433 decoding
## Files Added
- src/parser/rtl433_converter.py (~300 lines)
- src/matcher/rtl433_decoder.py (~400 lines)
- src/matcher/strategies.py (RTL433DecoderStrategy)
- docs/RTL433_INTEGRATION_PLAN.md
- docs/RTL433_IMPLEMENTATION_STATUS.md
- docs/RTL433_API_ENDPOINTS.md
- docs/PHASE8_COMPLETE.md
- tests/test_rtl433_integration.py
- tests/test_rtl433_api.sh
## Files Modified
- src/api/main_simple.py - Added RTL_433 decoding to upload
- src/api/routes/hardware.py - Added RTL_433 endpoints
## Performance
- Decode time: <0.05s per file
- 244 protocols supported
- 0.95 confidence for successful decodes
## Testing
- All integration tests passing
- All API endpoint tests passing
- ~3,600+ lines of code & documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
558 lines
12 KiB
Markdown
558 lines
12 KiB
Markdown
# 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 = `
|
|
<h3>RTL_433 Decoded (High Confidence)</h3>
|
|
${capture.rtl433_decoded.map(d => `
|
|
<div class="device">
|
|
<strong>${d.manufacturer} ${d.model}</strong>
|
|
<span class="confidence">${(d.confidence * 100).toFixed(0)}%</span>
|
|
<span class="protocol">Protocol ${d.protocol_id}</span>
|
|
</div>
|
|
`).join('')}
|
|
`;
|
|
container.appendChild(rtlSection);
|
|
}
|
|
|
|
// Show all matches
|
|
if (capture.matched_devices && capture.matched_devices.length > 0) {
|
|
const matchSection = document.createElement('div');
|
|
matchSection.innerHTML = `
|
|
<h3>All Matches</h3>
|
|
${capture.matched_devices.map(m => `
|
|
<div class="match">
|
|
<span>${m.device_name}</span>
|
|
<span class="method">${m.method}</span>
|
|
<span class="confidence">${(m.confidence * 100).toFixed(0)}%</span>
|
|
</div>
|
|
`).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`
|