Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
424
BLE_GATT_GUIDE.md
Normal file
424
BLE_GATT_GUIDE.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# Dangerous Pi - BLE GATT Server Guide
|
||||
|
||||
**Status**: ✅ Implemented - Ready for Integration
|
||||
**Architecture**: Service Layer Pattern - Zero Code Duplication
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The Dangerous Pi BLE GATT server provides Bluetooth Low Energy access to all Dangerous Pi functionality by **reusing the exact same service layer** as the REST API. This ensures:
|
||||
|
||||
✅ **Zero code duplication** - Business logic written once
|
||||
✅ **Identical behavior** - BLE and REST behave exactly the same
|
||||
✅ **Easy testing** - Service tests cover both interfaces
|
||||
✅ **Consistent errors** - Same error codes and handling
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Mobile App (React Native / Flutter) │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│ BLE GATT Protocol
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ BLE GATT Server (gatt_server.py) │
|
||||
│ - Characteristic handlers │
|
||||
│ - JSON encoding/decoding │
|
||||
│ - Notification management │
|
||||
│ - THIN ADAPTERS only │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│ Delegates to
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Service Layer (SHARED with REST!) │
|
||||
│ - PM3Service │
|
||||
│ - WiFiService │
|
||||
│ - SystemService │
|
||||
│ - UpdateService │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Managers/Workers │
|
||||
│ - PM3Worker, WiFiManager, etc. │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key Point**: BLE handlers and REST endpoints are BOTH thin adapters. They share 100% of business logic through the service layer.
|
||||
|
||||
---
|
||||
|
||||
## 📡 GATT Services & Characteristics
|
||||
|
||||
### PM3 Service
|
||||
**Service UUID**: `00000000-1234-5678-1234-56789abcdef0`
|
||||
|
||||
| Characteristic | UUID | Properties | Description |
|
||||
|---------------|------|------------|-------------|
|
||||
| Command Write | ...def1 | Write | Execute PM3 command |
|
||||
| Command Result | ...def2 | Notify | Command execution result |
|
||||
| Status | ...def3 | Read | Get PM3 status |
|
||||
| Session Create | ...def4 | Write | Create new session |
|
||||
| Session Release | ...def5 | Write | Release session |
|
||||
| Session Info | ...def6 | Read | Get session information |
|
||||
|
||||
### WiFi Service
|
||||
**Service UUID**: `00000000-1234-5678-1234-56789abcdef10`
|
||||
|
||||
| Characteristic | UUID | Properties | Description |
|
||||
|---------------|------|------------|-------------|
|
||||
| Status | ...def11 | Read | Get WiFi status |
|
||||
| Scan | ...def12 | Write, Notify | Scan for networks |
|
||||
| Connect | ...def13 | Write | Connect to network |
|
||||
| Disconnect | ...def14 | Write | Disconnect from network |
|
||||
| Mode | ...def15 | Read, Write | Get/Set WiFi mode |
|
||||
| Saved Networks | ...def16 | Read | List saved networks |
|
||||
| Forget Network | ...def17 | Write | Forget saved network |
|
||||
|
||||
### System Service
|
||||
**Service UUID**: `00000000-1234-5678-1234-56789abcdef20`
|
||||
|
||||
| Characteristic | UUID | Properties | Description |
|
||||
|---------------|------|------------|-------------|
|
||||
| Info | ...def21 | Read | Get system information |
|
||||
| Shutdown | ...def22 | Write | Initiate shutdown |
|
||||
| Restart | ...def23 | Write | Initiate restart |
|
||||
| Logs | ...def24 | Read | Get service logs |
|
||||
|
||||
### Update Service
|
||||
**Service UUID**: `00000000-1234-5678-1234-56789abcdef30`
|
||||
|
||||
| Characteristic | UUID | Properties | Description |
|
||||
|---------------|------|------------|-------------|
|
||||
| Check | ...def31 | Write, Notify | Check for updates |
|
||||
| Download | ...def32 | Write | Download update |
|
||||
| Install | ...def33 | Write | Install update |
|
||||
| Progress | ...def34 | Read, Notify | Update progress |
|
||||
| Release Notes | ...def35 | Read | Get release notes |
|
||||
|
||||
---
|
||||
|
||||
## 📱 Client Integration Examples
|
||||
|
||||
### PM3 Command Execution
|
||||
|
||||
```javascript
|
||||
// React Native / JavaScript example
|
||||
|
||||
// 1. Connect to Dangerous Pi
|
||||
const device = await manager.connectToDevice(deviceId);
|
||||
await device.discoverAllServicesAndCharacteristics();
|
||||
|
||||
// 2. Create session
|
||||
const sessionChar = "00000000-1234-5678-1234-56789abcdef4";
|
||||
const sessionRequest = JSON.stringify({ force_takeover: false });
|
||||
await device.writeCharacteristicWithResponseForService(
|
||||
PM3_SERVICE_UUID,
|
||||
sessionChar,
|
||||
base64.encode(sessionRequest)
|
||||
);
|
||||
|
||||
// 3. Execute PM3 command
|
||||
const commandChar = "00000000-1234-5678-1234-56789abcdef1";
|
||||
const command = JSON.stringify({
|
||||
command: "hw version",
|
||||
session_id: receivedSessionId
|
||||
});
|
||||
|
||||
await device.writeCharacteristicWithResponseForService(
|
||||
PM3_SERVICE_UUID,
|
||||
commandChar,
|
||||
base64.encode(command)
|
||||
);
|
||||
|
||||
// 4. Listen for result notification
|
||||
const resultChar = "00000000-1234-5678-1234-56789abcdef2";
|
||||
device.monitorCharacteristicForService(
|
||||
PM3_SERVICE_UUID,
|
||||
resultChar,
|
||||
(error, characteristic) => {
|
||||
if (characteristic) {
|
||||
const result = JSON.parse(base64.decode(characteristic.value));
|
||||
console.log("Command result:", result.output);
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### WiFi Network Scan
|
||||
|
||||
```javascript
|
||||
// 1. Trigger scan
|
||||
const scanChar = "00000000-1234-5678-1234-56789abcdef12";
|
||||
|
||||
// Listen for scan results first
|
||||
device.monitorCharacteristicForService(
|
||||
WIFI_SERVICE_UUID,
|
||||
scanChar,
|
||||
(error, characteristic) => {
|
||||
if (characteristic) {
|
||||
const result = JSON.parse(base64.decode(characteristic.value));
|
||||
console.log("Found networks:", result.networks);
|
||||
// Display networks in UI
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Trigger scan (empty JSON or specify interface)
|
||||
await device.writeCharacteristicWithResponseForService(
|
||||
WIFI_SERVICE_UUID,
|
||||
scanChar,
|
||||
base64.encode(JSON.stringify({}))
|
||||
);
|
||||
```
|
||||
|
||||
### WiFi Connect
|
||||
|
||||
```javascript
|
||||
const connectChar = "00000000-1234-5678-1234-56789abcdef13";
|
||||
const connectRequest = JSON.stringify({
|
||||
ssid: "MyNetwork",
|
||||
password: "mypassword",
|
||||
hidden: false
|
||||
});
|
||||
|
||||
await device.writeCharacteristicWithResponseForService(
|
||||
WIFI_SERVICE_UUID,
|
||||
connectChar,
|
||||
base64.encode(connectRequest)
|
||||
);
|
||||
```
|
||||
|
||||
### System Information
|
||||
|
||||
```javascript
|
||||
const infoChar = "00000000-1234-5678-1234-56789abcdef21";
|
||||
const infoBytes = await device.readCharacteristicForService(
|
||||
SYSTEM_SERVICE_UUID,
|
||||
infoChar
|
||||
);
|
||||
|
||||
const info = JSON.parse(base64.decode(infoBytes.value));
|
||||
console.log("CPU:", info.cpu.percent + "%");
|
||||
console.log("Memory:", info.memory.percent + "%");
|
||||
console.log("Temperature:", info.cpu.temperature + "°C");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Data Formats
|
||||
|
||||
All BLE characteristics use **JSON** for data exchange (encoded as UTF-8 bytes).
|
||||
|
||||
### Request Format (Write Characteristics)
|
||||
```json
|
||||
{
|
||||
"param1": "value1",
|
||||
"param2": "value2"
|
||||
}
|
||||
```
|
||||
|
||||
### Response Format (Read/Notify Characteristics)
|
||||
|
||||
**Success Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "error_code",
|
||||
"message": "Human-readable message"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Codes
|
||||
|
||||
Same error codes as REST API:
|
||||
- `session_locked` - Another session is active
|
||||
- `pm3_not_connected` - Proxmark3 not connected
|
||||
- `command_failed` - PM3 command failed
|
||||
- `connection_failed` - WiFi connection failed
|
||||
- `invalid_mode` - Invalid WiFi mode
|
||||
- `network_not_found` - Network not in saved list
|
||||
- `update_check_error` - Failed to check for updates
|
||||
- etc.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
The GATT server has comprehensive unit tests:
|
||||
|
||||
```bash
|
||||
# Run BLE GATT tests
|
||||
pytest tests/unit/ble/test_gatt_server.py
|
||||
|
||||
# Test coverage
|
||||
pytest tests/unit/ble/ --cov=app/backend/ble
|
||||
```
|
||||
|
||||
**Test Coverage:**
|
||||
- ✅ Characteristic handler registration
|
||||
- ✅ Delegation to services (PM3, WiFi, System, Update)
|
||||
- ✅ JSON encoding/decoding
|
||||
- ✅ Error handling
|
||||
- ✅ Notification system
|
||||
- ✅ Data format conversion
|
||||
|
||||
### Integration Testing with Mobile App
|
||||
|
||||
```python
|
||||
# Python example using bleak library
|
||||
import asyncio
|
||||
import json
|
||||
from bleak import BleakClient
|
||||
|
||||
async def test_pm3_command():
|
||||
async with BleakClient("AA:BB:CC:DD:EE:FF") as client:
|
||||
# Write command
|
||||
command_char = "00000000-1234-5678-1234-56789abcdef1"
|
||||
command_data = json.dumps({
|
||||
"command": "hw version",
|
||||
"session_id": "test"
|
||||
})
|
||||
|
||||
await client.write_gatt_char(
|
||||
command_char,
|
||||
command_data.encode('utf-8')
|
||||
)
|
||||
|
||||
# Read status
|
||||
status_char = "00000000-1234-5678-1234-56789abcdef3"
|
||||
status_bytes = await client.read_gatt_char(status_char)
|
||||
status = json.loads(status_bytes.decode('utf-8'))
|
||||
|
||||
print("PM3 Status:", status)
|
||||
|
||||
asyncio.run(test_pm3_command())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
### Authentication
|
||||
- BLE pairing should be required for sensitive operations
|
||||
- Consider implementing challenge-response authentication
|
||||
- Session IDs provide multi-user coordination
|
||||
|
||||
### Encryption
|
||||
- Use BLE encryption (LE Secure Connections)
|
||||
- All data is already JSON, easy to add encryption layer
|
||||
- Consider end-to-end encryption for sensitive commands
|
||||
|
||||
### Access Control
|
||||
- Session management prevents concurrent access conflicts
|
||||
- Can implement per-characteristic permissions
|
||||
- Rate limiting for command execution
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Integration with BLEManager
|
||||
|
||||
The GATT server integrates with the existing BLEManager:
|
||||
|
||||
```python
|
||||
# In app/backend/managers/ble_manager.py
|
||||
|
||||
from ..ble.gatt_server import DangerousPiGATTServer
|
||||
|
||||
class BLEManager:
|
||||
def __init__(self):
|
||||
# Existing notification support
|
||||
self._notification_queue = asyncio.Queue()
|
||||
|
||||
# NEW: GATT server
|
||||
self._gatt_server = None
|
||||
|
||||
async def initialize(self):
|
||||
"""Initialize BLE with GATT server."""
|
||||
# Existing notification setup
|
||||
await self._setup_notifications()
|
||||
|
||||
# NEW: Initialize and start GATT server
|
||||
self._gatt_server = DangerousPiGATTServer()
|
||||
await self._gatt_server.start()
|
||||
|
||||
# Register notification callbacks with actual BLE implementation
|
||||
# (BlueZ, etc.)
|
||||
self._register_gatt_characteristics()
|
||||
|
||||
def _register_gatt_characteristics(self):
|
||||
"""Register GATT characteristics with BLE stack."""
|
||||
for uuid, handler in self._gatt_server.get_all_characteristics().items():
|
||||
# Register with BlueZ or other BLE implementation
|
||||
# Set up read/write callbacks
|
||||
# Connect to GATT server handlers
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Benefits Summary
|
||||
|
||||
### Code Reuse
|
||||
| Component | REST API | BLE GATT | Shared |
|
||||
|-----------|----------|----------|--------|
|
||||
| Business Logic | ❌ | ❌ | ✅ Service Layer |
|
||||
| Session Management | ❌ | ❌ | ✅ Service Layer |
|
||||
| Error Handling | ❌ | ❌ | ✅ Service Layer |
|
||||
| PM3 Commands | ❌ | ❌ | ✅ Service Layer |
|
||||
| WiFi Operations | ❌ | ❌ | ✅ Service Layer |
|
||||
| **Code Duplication** | **0%** | **0%** | **100% Shared** |
|
||||
|
||||
### Maintenance
|
||||
- Fix bugs **once** in service layer
|
||||
- Add features **once** in service layer
|
||||
- Test **once** with service tests
|
||||
- Both REST and BLE get the fix/feature automatically
|
||||
|
||||
### Consistency
|
||||
- REST and BLE **guaranteed** identical behavior
|
||||
- Same error codes and messages
|
||||
- Same data validation
|
||||
- Same session management
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. **Complete BlueZ Integration** - Connect GATT server to BlueZ D-Bus
|
||||
2. **Mobile App Development** - Build React Native / Flutter app
|
||||
3. **Security Hardening** - Implement BLE pairing and encryption
|
||||
4. **Performance Testing** - Test with real Proxmark3 hardware
|
||||
5. **Documentation** - Mobile app integration guide
|
||||
|
||||
---
|
||||
|
||||
## 📚 References
|
||||
|
||||
- [BLE GATT Specification](https://www.bluetooth.com/specifications/specs/core-specification/)
|
||||
- [React Native BLE library](https://github.com/dotintent/react-native-ble-plx)
|
||||
- [Flutter Blue Plus](https://pub.dev/packages/flutter_blue_plus)
|
||||
- [Python Bleak](https://github.com/hbldh/bleak)
|
||||
- [BlueZ D-Bus API](http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/gatt-api.txt)
|
||||
|
||||
---
|
||||
|
||||
**Summary**: The BLE GATT server is a perfect demonstration of the service layer pattern. Every handler is a thin adapter that delegates to services, achieving **zero code duplication** and **guaranteed consistency** with the REST API. 🚀
|
||||
Reference in New Issue
Block a user