tahamajs/CPS / Files /ComputerAssignments /CA2 /code /docs /AirMouseCommunicationProtocol.md
tahamajs's picture
|
download
raw
43.2 kB
# Air Mouse Communication Protocol – Complete Documentation
## Table of Contents
1. [Protocol Overview](#protocol-overview)
2. [Connection & Pairing Flow](#connection--pairing-flow)
3. [Transport Protocols](#transport-protocols)
4. [Message Specification](#message-specification)
5. [Message Types Reference](#message-types-reference)
6. [Gesture Recognition](#gesture-recognition)
7. [Proximity Lock/Unlock](#proximity-lockunlock)
8. [Connection Quality Monitoring](#connection-quality-monitoring)
9. [Security & Authentication](#security--authentication)
10. [Error Handling](#error-handling)
11. [Protocol Flow Diagrams](#protocol-flow-diagrams)
12. [Android Implementation Guide](#android-implementation-guide)
13. [Go Server Implementation Guide](#go-server-implementation-guide)
14. [API Reference](#api-reference)
15. [Troubleshooting](#troubleshooting)
---
## Protocol Overview
The Air Mouse protocol is designed for **low-latency real-time control** between an Android device (client) and a desktop Go server. It supports multiple transport protocols, optional gesture recognition, and proximity-based auto-lock/unlock.
### Key Characteristics
| Property | Value |
|----------|-------|
| **Primary Transport** | WebSocket over TCP |
| **Fallback Transport** | Raw TCP |
| **Discovery Protocol** | UDP Broadcast |
| **Message Format** | JSON (UTF-8) |
| **Message Delimiter** | Newline (`\n`) |
| **Default Ports** | TCP: 8080, WebSocket: 8081, UDP: 8082 |
| **Heartbeat Interval** | 30 seconds |
| **Reconnection Strategy** | Exponential backoff (max 10 attempts) |
### Supported Platforms
| Platform | WebSocket | TCP | UDP Discovery | Bluetooth HID | USB |
|----------|-----------|-----|---------------|---------------|-----|
| **Android** | ✅ | ✅ | ✅ | ✅ (BLE) | ✅ (USB-C) |
| **Go Server** | ✅ | ✅ | ✅ | ✅ | ✅ (Linux) |
| **Windows Client** | ✅ | ✅ | ✅ | ❌ | ❌ |
| **macOS Client** | ✅ | ✅ | ✅ | ❌ | ❌ |
---
## Connection & Pairing Flow
### Standard Connection Flow
```
┌─────────────┐ ┌─────────────┐
│ Android │ │ Go Server │
│ Client │ │ │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. WebSocket Upgrade Request │
│─────────────────────────────────>│
│ │
│ 2. 101 Switching Protocols │
│<─────────────────────────────────│
│ │
│ 3. Hello Message │
│─────────────────────────────────>│
│ {"type":"hello","payload":{ │
│ "name":"Pixel 8","version":"3.0"}}│
│ │
│ 4. Welcome Message │
│<─────────────────────────────────│
│ {"type":"welcome","payload":{ │
│ "server":"AirMouse","version":"3.0"}}│
│ │
│ 5. Move/Click/Scroll Messages │
│<────────────────────────────────>│
│ │
│ 6. Periodic Ping/Pong (30s) │
│<────────────────────────────────>│
│ │
```
### Pairing Flow (QR Code)
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Android │ │ Server │ │ Android │
│ App │ │ (QR) │ │ Scanner │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ 1. Generate QR Code │ │
│<──────────────────────│ │
│ │ │
│ 2. Scan QR Code │ │
│──────────────────────────────────────────────>│
│ │ │
│ 3. Extract URL & Token │
│<──────────────────────────────────────────────│
│ │ │
│ 4. Connect with Token │
│──────────────────────>│ │
│ ws://server:8081/ws?token=<jwt> │
│ │ │
│ 5. Validate Token │ │
│ │ │
│ 6. Connection Established │
│<──────────────────────│ │
│ │ │
```
---
## Transport Protocols
### WebSocket (Primary)
**Endpoint:** `ws://<server-ip>:8081/ws`
**Features:**
- Full-duplex communication
- Built-in ping/pong (30s interval)
- Binary message support
- Automatic reconnection
**Connection Example:**
```kotlin
// Android
val client = OkHttpClient.Builder()
.pingInterval(30, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("ws://192.168.1.100:8081/ws")
.build()
client.newWebSocket(request, listener)
```
### TCP (Fallback)
**Endpoint:** `<server-ip>:8080`
**Features:**
- Simple text-based protocol
- Line-delimited messages
- No built-in heartbeat
**Connection Example:**
```kotlin
// Android
val socket = Socket().apply {
connect(InetSocketAddress("192.168.1.100", 8080), 5000)
}
val writer = PrintWriter(socket.getOutputStream(), true)
val reader = BufferedReader(InputStreamReader(socket.getInputStream()))
```
### UDP Discovery
**Endpoint:** Broadcast on port 8082
**Discovery Message:**
```
AIRMOUSE_DISCOVERY
```
**Response Format (Legacy):**
```
AIRMOUSE_SERVER:8080:AirMouse Pro
```
**Response Format (JSON):**
```json
{
"type": "discovery_response",
"port": 8080,
"ip": "192.168.1.100",
"name": "Air Mouse Pro",
"version": "3.0"
}
```
---
## Message Specification
### Message Structure (Nested Format)
```json
{
"type": "message_type",
"payload": {
"field1": "value1",
"field2": "value2"
},
"id": "optional_request_id"
}
```
### Message Structure (Flat Format - Android Default)
```json
{
"type": "message_type",
"field1": "value1",
"field2": "value2"
}
```
### Field Definitions
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | String | **Yes** | Message type identifier |
| `payload` | Object | No | Nested payload (alternative to flat fields) |
| `id` | String/Number | No | Request ID for acknowledgment tracking |
---
## Message Types Reference
### 1. `move` – Cursor Movement
**Direction:** Client → Server
**Description:** Sends relative cursor movement delta.
**Flat Format (Android):**
```json
{
"type": "move",
"dx": 12.5,
"dy": -3.2
}
```
**Nested Format:**
```json
{
"type": "move",
"payload": {
"dx": 12.5,
"dy": -3.2
}
}
```
**Fields:**
| Field | Type | Range | Description |
|-------|------|-------|-------------|
| `dx` | Float | -32768 to 32767 | Horizontal movement (positive = right) |
| `dy` | Float | -32768 to 32767 | Vertical movement (positive = down) |
---
### 2. `click` – Mouse Click
**Direction:** Client → Server
**Description:** Simulates a mouse button click.
**Flat Format:**
```json
{
"type": "click",
"button": "left",
"id": 12345
}
```
**Nested Format:**
```json
{
"type": "click",
"payload": {
"button": "left"
},
"id": 12345
}
```
**Fields:**
| Field | Type | Values | Description |
|-------|------|--------|-------------|
| `button` | String | `left`, `right`, `middle` | Mouse button to click |
| `id` | Number/String | Optional | Request ID for ACK |
---
### 3. `doubleclick` – Double Click
**Direction:** Client → Server
**Description:** Simulates a double left click.
**Format:**
```json
{
"type": "doubleclick",
"id": 12346
}
```
---
### 4. `rightclick` – Right Click (Convenience)
**Direction:** Client → Server
**Description:** Simulates a right click.
**Format:**
```json
{
"type": "rightclick",
"id": 12347
}
```
---
### 5. `scroll` – Scroll Wheel
**Direction:** Client → Server
**Description:** Simulates scroll wheel movement.
**Flat Format:**
```json
{
"type": "scroll",
"delta": 3,
"id": 12348
}
```
**Nested Format:**
```json
{
"type": "scroll",
"payload": {
"delta": 3
},
"id": 12348
}
```
**Fields:**
| Field | Type | Range | Description |
|-------|------|-------|-------------|
| `delta` | Integer | -127 to 127 | Positive = scroll up, negative = scroll down |
---
### 6. `hello` – Device Identification
**Direction:** Client → Server
**Description:** Identifies the client device to the server.
**Flat Format:**
```json
{
"type": "hello",
"name": "Pixel 8 Pro",
"version": "3.0",
"device": "Google Pixel 8",
"android_version": "14"
}
```
**Nested Format:**
```json
{
"type": "hello",
"payload": {
"name": "Pixel 8 Pro",
"version": "3.0",
"device": "Google Pixel 8",
"android_version": "14"
}
}
```
**Fields:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | String | Yes | User-defined device name |
| `version` | String | Yes | App version (e.g., "3.0") |
| `device` | String | No | Device model |
| `android_version` | String | No | Android OS version |
**Server Response:** `welcome`
---
### 7. `gesture` – Gesture Recognition
**Direction:** Client → Server
**Description:** Sends a recognised gesture from the Android ML model.
**Format:**
```json
{
"type": "gesture",
"payload": {
"gesture": "ThumbsUp",
"confidence": 0.92
}
}
```
**Fields:**
| Field | Type | Range | Description |
|-------|------|-------|-------------|
| `gesture` | String | See [Gesture Types](#gesture-types) | Recognised gesture name |
| `confidence` | Float | 0.0 to 1.0 | Confidence score (≥0.7 recommended) |
---
### 8. `proximity` – Proximity Update
**Direction:** Client → Server
**Description:** Sends estimated distance to the computer for auto lock/unlock.
**Format:**
```json
{
"type": "proximity",
"payload": {
"device_id": "abc123",
"is_near": true,
"distance": 1.23
}
}
```
**Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `device_id` | String | Unique device identifier (Android ID) |
| `is_near` | Boolean | True if distance < near_threshold |
| `distance` | Float | Estimated distance in meters |
---
### 9. `control` – Control Command
**Direction:** Client → Server
**Description:** Sends system control commands.
**Format:**
```json
{
"type": "control",
"payload": {
"command": "pause_movement"
}
}
```
**Supported Commands:**
| Command | Description |
|---------|-------------|
| `pause_movement` | Pause cursor movement |
| `resume_movement` | Resume cursor movement |
| `lock_screen` | Lock the computer screen |
| `unlock_screen` | Unlock the computer screen |
| `calibrate` | Recalibrate sensors |
| `reset` | Reset movement state |
| `play_pause` | Play/Pause media |
| `next_track` | Next track |
| `prev_track` | Previous track |
| `volume_up` | Increase volume |
| `volume_down` | Decrease volume |
| `mute` | Mute audio |
| `show_desktop` | Show desktop |
| `task_view` | Open task view |
| `switch_window` | Switch between windows |
| `window_maximize` | Maximize window |
| `window_minimize` | Minimize window |
| `window_close` | Close window |
| `browser_back` | Browser back |
| `browser_forward` | Browser forward |
| `browser_refresh` | Refresh page |
| `browser_home` | Go to home page |
| `zoom_in` | Zoom in |
| `zoom_out` | Zoom out |
---
### 10. `ping` / `pong` – Heartbeat
**Direction:** Bidirectional
**Description:** Keep-alive messages to detect connection drops.
**Ping (Client → Server):**
```json
{
"type": "ping"
}
```
**Pong (Server → Client):**
```json
{
"type": "pong"
}
```
---
### 11. `welcome` – Server Welcome
**Direction:** Server → Client
**Description:** Sent after successful `hello` message.
**Format:**
```json
{
"type": "welcome",
"payload": {
"server": "Air Mouse Pro",
"version": "3.0",
"id": "client-assigned-id"
}
}
```
---
### 12. `ack` – Acknowledgment
**Direction:** Server → Client
**Description:** Acknowledges receipt of a command with an ID.
**Format:**
```json
{
"type": "ack",
"id": "12345",
"status": "ok",
"message": "optional message"
}
```
---
### 13. `error` – Error Message
**Direction:** Server → Client
**Description:** Reports an error condition.
**Format:**
```json
{
"type": "error",
"payload": {
"code": 400,
"message": "Invalid message format"
}
}
```
---
## Gesture Recognition
### Gesture Types
| Gesture | Default Action | Confidence Threshold |
|---------|----------------|---------------------|
| `ThumbsUp` | Play/Pause | 0.7 |
| `ThumbsDown` | Stop | 0.7 |
| `SwipeLeft` | Previous Track | 0.6 |
| `SwipeRight` | Next Track | 0.6 |
| `SwipeUp` | Volume Up | 0.6 |
| `SwipeDown` | Volume Down | 0.6 |
| `CircleCW` | Volume Up | 0.65 |
| `CircleCCW` | Volume Down | 0.65 |
| `PinchIn` | Zoom Out | 0.7 |
| `PinchOut` | Zoom In | 0.7 |
| `DoubleTap` | Play/Pause | 0.65 |
| `LongPress` | Right Click | 0.7 |
| `Shake` | Undo/Reset | 0.75 |
| `Peace` | Lock Screen | 0.7 |
| `Fist` | Mute | 0.7 |
| `ZoomIn` | Zoom In | 0.7 |
| `ZoomOut` | Zoom Out | 0.7 |
### Gesture Pipeline
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Sensors │───▶│ Gesture │───▶│ Confidence │───▶│ Send to │
│ (Gyro/Accel)│ │ Detection │ │ Filter │ │ Server │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Action │◀───│ Gesture │◀───│ Confidence │◀───│ Message │
│ Execution │ │ Mapping │ │ Check │ │ Reception │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
```
---
## Proximity Lock/Unlock
### Overview
The proximity feature uses Bluetooth RSSI (Received Signal Strength Indicator) to estimate the distance between the phone and the computer. When the user walks away beyond the `far_threshold`, the screen locks automatically. When they return within the `near_threshold`, the screen unlocks.
### Distance Calculation
The distance is calculated using the path loss model:
```
distance = 10^((TxPower - RSSI) / (10 * n))
```
Where:
- `TxPower` = RSSI at 1 meter (calibrated, typically -59 dBm)
- `n` = Path loss exponent (2.0 to 4.0, default 2.5)
### Thresholds
| Threshold | Default | Description |
|-----------|---------|-------------|
| `near_threshold` | 1.5 m | Distance to unlock (when approaching) |
| `far_threshold` | 3.0 m | Distance to lock (when walking away) |
### Hysteresis
To prevent rapid toggling, the system uses hysteresis:
```
if (isNear) {
// Already near - need to go beyond far_threshold to change
isNear = distance < far_threshold
} else {
// Currently far - need to go within near_threshold to change
isNear = distance < near_threshold
}
```
### Proximity Flow
```
┌─────────────┐ ┌─────────────┐
│ Android │ │ Go Server │
│ Client │ │ │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. RSSI Measurement │
│ (every 1 second) │
│ │
│ 2. Distance Calculation │
│ │
│ 3. Proximity Message │
│─────────────────────────────────>│
│ {"type":"proximity", │
│ "payload":{ │
│ "is_near":false, │
│ "distance":4.2 │
│ }} │
│ │
│ 4. Check Thresholds │
│ distance > far_threshold │
│ │
│ 5. Lock Screen │
│ (platform-specific) │
│ │
│ 6. Optional: Lock Ack │
│<─────────────────────────────────│
│ │
```
---
## Connection Quality Monitoring
### Quality Metrics
| Metric | Description | Good Range |
|--------|-------------|------------|
| **Ping** | Round-trip latency | < 50 ms |
| **Jitter** | Latency variance | < 10 ms |
| **Packet Loss** | Lost message percentage | < 1% |
| **RSSI** | Signal strength (Bluetooth) | > -60 dBm |
### Quality Categories
| Category | Ping | RSSI | Color |
|----------|------|------|-------|
| **Excellent** | < 30 ms | > -50 dBm | 🟢 Green |
| **Good** | 30-60 ms | -50 to -60 dBm | 🟢 Green |
| **Fair** | 60-100 ms | -60 to -70 dBm | 🟡 Yellow |
| **Poor** | 100-200 ms | -70 to -80 dBm | 🟠 Orange |
| **Very Poor** | > 200 ms | < -80 dBm | 🔴 Red |
### Quality Message (Server → Client)
```json
{
"type": "quality",
"payload": {
"ping": 45,
"jitter": 5,
"packet_loss": 0.02,
"signal_strength": "GOOD"
}
}
```
---
## Security & Authentication
### Authentication Methods
#### 1. JWT Token (Recommended)
The server generates a JWT token embedded in the QR code.
**QR Code Format:**
```
airmouse://pair?token=<jwt>&ws=ws://<server-ip>:<port>/ws
```
**WebSocket Connection:**
```
ws://192.168.1.100:8081/ws?token=<jwt>
```
#### 2. Pre-shared Token
Configure static tokens in `config.json`:
```json
{
"security": {
"auth_enabled": true,
"auth_tokens": ["token1", "token2"]
}
}
```
#### 3. No Authentication (Development)
Set `auth_enabled: false` in configuration.
### Token Validation (Server Side)
```go
func (s *Server) validateToken(token string) bool {
// Parse JWT
claims, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return s.secret, nil
})
if err != nil {
return false
}
// Check expiry
exp, ok := claims["exp"].(float64)
if !ok || time.Now().Unix() > int64(exp) {
return false
}
return true
}
```
---
## Error Handling
### Error Codes
| Code | Name | Description |
|------|------|-------------|
| 400 | `BAD_REQUEST` | Malformed JSON or missing required fields |
| 401 | `UNAUTHORIZED` | Invalid or expired authentication token |
| 404 | `NOT_FOUND` | Endpoint not found |
| 429 | `TOO_MANY_REQUESTS` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Server internal error |
| 503 | `SERVICE_UNAVAILABLE` | Server temporarily unavailable |
### Error Response Format
```json
{
"type": "error",
"payload": {
"code": 400,
"message": "Invalid message format: missing 'type' field",
"details": "Expected 'type' to be one of: move, click, scroll, hello, gesture, proximity, control"
}
}
```
### Client Error Handling Strategy
```kotlin
connectionManager.onError = { error ->
when {
error.contains("401") -> {
// Token expired - re-pair
showPairingDialog()
}
error.contains("429") -> {
// Rate limited - reduce message frequency
reduceMoveRate()
}
error.contains("500") -> {
// Server error - retry with backoff
scheduleReconnectWithBackoff()
}
else -> {
// Generic error - show notification
showToast("Connection error: $error")
}
}
}
```
---
## Protocol Flow Diagrams
### Complete Message Flow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ MESSAGE FLOW DIAGRAM │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client (Android) Server (Go) │
│ ──────────────── ─────────── │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 1. WebSocket │──────────────────▶│ │ │
│ │ Upgrade │ │ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 2. Hello │──────────────────▶│ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Validate │ │ │
│ │ │ Client │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 3. Welcome │◀──────────────────│ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ NORMAL OPERATION │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 4. Move │──────────────────▶│ ┌─────────────┐ │ │
│ └─────────────────┘ │ │ Move Mouse │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 5. Click │──────────────────▶│ ┌─────────────┐ │ │
│ └─────────────────┘ │ │ Click │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ ┌─────────────┐ │ │
│ │ 6. ACK (opt) │◀──────────────────│ │ Send ACK │ │ │
│ └─────────────────┘ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐┌─────────────────┐ │ │ │
│ 7. Gesture │──────────────────▶│ ┌─────────────┐ │ │
│ │ │ │ Map Gesture │ │ │
│ │ │ │ to Action │ │ │
│ │ │ └─────────────┘ │ │
│ │ │ │ │
│ │ │ ┌─────────────┐ │ │
│ │ │ │ Execute │ │ │
│ │ │ │ System │ │ │
│ │ │ │ Action │ │ │
│ │ │ └─────────────┘ │ │
│ │ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 8. Proximity │────────────────▶│ ┌─────────────┐ │ │
│ │ Update │ │ │ Check │ │ │
│ └─────────────────┘ │ │ Thresholds │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Lock/Unlock │ │ │
│ │ │ Screen │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 9. Ping │────────────────▶│ ┌─────────────┐ │ │
│ │ (every 30s) │ │ │ Send Pong │ │ │
│ └─────────────────┘ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 10. Pong │◀────────────────│ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ RECONNECTION FLOW │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ Connection Lost │ │ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ Exponential │ │ │ │
│ │ Backoff Delay │ │ │ │
│ │ (1s,2s,4s,8s) │ │ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 11. Reconnect │────────────────▶│ ┌─────────────┐ │ │
│ │ Attempt │ │ │ Reconnect │ │ │
│ └─────────────────┘ │ │ Accepted │ │ │
│ │ └─────────────┘ │ │
│ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ 12. Re-Hello │────────────────▶│ │ │
│ └─────────────────┘ │ │ │
│ │ │ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Android Implementation Guide
### Dependencies (build.gradle)
```groovy
dependencies {
// WebSocket
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
// JSON parsing
implementation 'com.google.code.gson:gson:2.10.1'
// Dependency Injection
implementation 'com.google.dagger:hilt-android:2.48'
// TensorFlow Lite (for gesture recognition)
implementation 'org.tensorflow:tensorflow-lite:2.14.0'
// Bluetooth
implementation 'androidx.core:core-ktx:1.12.0'
}
```
### ConnectionManager Usage Example
```kotlin
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var connectionManager: ConnectionManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Observe connection status
lifecycleScope.launch {
connectionManager.connectionStatus.collect { status ->
when (status) {
ConnectionManager.ConnectionStatus.CONNECTED -> {
showConnected()
connectionManager.sendHello(Build.MODEL, "3.0")
}
ConnectionManager.ConnectionStatus.CONNECTING -> showConnecting()
ConnectionManager.ConnectionStatus.DISCONNECTED -> showDisconnected()
ConnectionManager.ConnectionStatus.ERROR -> showError()
else -> {}
}
}
}
// Observe connection quality
lifecycleScope.launch {
connectionManager.connectionQuality.collect { quality ->
updateSignalIcon(quality.level())
updateLatencyDisplay("${quality.ping} ms")
}
}
// Send movement (from sensor callback)
fun onSensorChanged(dx: Float, dy: Float) {
connectionManager.sendMove(dx, dy)
}
// Send click
fun onClick() {
connectionManager.sendClick("left")
}
// Send gesture
fun onGestureDetected(gesture: String, confidence: Float) {
if (confidence > 0.7f) {
connectionManager.sendGesture(gesture, confidence)
}
}
// Send proximity update
fun onProximityChanged(distance: Float, isNear: Boolean) {
connectionManager.sendProximity(isNear, distance)
}
}
}
```
### Hello Message with Device Info
```kotlin
fun sendHello() {
val deviceInfo = JSONObject().apply {
put("type", "hello")
put("payload", JSONObject().apply {
put("name", Build.MODEL)
put("version", BuildConfig.VERSION_NAME)
put("device", "${Build.MANUFACTURER} ${Build.MODEL}")
put("android_version", Build.VERSION.RELEASE)
})
}
connectionManager.send(deviceInfo.toString())
}
```
---
## Go Server Implementation Guide
### Protocol Server Structure
```go
type ProtocolServer struct {
tcpServer *TCPServer
wsServer *WebSocketServer
udpServer *UDPServer
mouseCtrl MouseController
deviceMgr *DeviceManager
authMgr *AuthManager
}
func (s *ProtocolServer) Start() error {
// Start WebSocket server
go s.wsServer.Start()
// Start TCP fallback
go s.tcpServer.Start()
// Start UDP discovery
go s.udpServer.Start()
return nil
}
```
### Message Handler
```go
func (h *Handler) processMessage(client *Client, msgType string, payload map[string]interface{}, id *string) {
switch msgType {
case "move":
dx := getFloat(payload, "dx")
dy := getFloat(payload, "dy")
h.mouse.Move(dx, dy)
case "click":
button := getString(payload, "button", "left")
h.mouse.Click(button)
h.sendAck(client, id)
case "gesture":
gesture := getString(payload, "gesture", "")
confidence := getFloat(payload, "confidence")
if confidence > 0.7 {
h.executeGesture(gesture)
}
case "proximity":
isNear := getBool(payload, "is_near")
distance := getFloat(payload, "distance")
h.proximityMgr.ProcessUpdate(isNear, distance)
case "control":
command := getString(payload, "command", "")
h.executeControl(command)
case "hello":
name := getString(payload, "name", "")
client.SetName(name)
h.sendWelcome(client)
}
}
```
### Welcome Message
```go
func (h *Handler) sendWelcome(client *Client) {
welcome := map[string]interface{}{
"type": "welcome",
"payload": map[string]string{
"server": h.cfg.ServerName,
"version": h.cfg.Version,
"id": client.ID,
},
}
data, _ := json.Marshal(welcome)
client.Send <- append(data, '\n')
}
```
---
## API Reference
### WebSocket Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/ws` | WebSocket | Primary WebSocket connection |
| `/ws?token=<jwt>` | WebSocket | Authenticated WebSocket connection |
### HTTP Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Health check |
| `/api/status` | GET | Server status |
| `/api/stats` | GET | Statistics |
| `/api/devices` | GET | Connected devices list |
| `/api/qrcode` | GET | Generate pairing QR code |
| `/api/config` | GET/POST | Get/update configuration |
| `/api/start` | POST | Start server |
| `/api/stop` | POST | Stop server |
### Rate Limits
| Message Type | Rate Limit | Window |
|--------------|------------|--------|
| `move` | 120 msg/sec | 1 second |
| `click` | 20 msg/sec | 1 second |
| `scroll` | 20 msg/sec | 1 second |
| `gesture` | 10 msg/sec | 1 second |
| `proximity` | 5 msg/sec | 1 second |
| `control` | 10 msg/sec | 1 second |
---
## Troubleshooting
### Common Issues and Solutions
| Issue | Possible Cause | Solution |
|-------|----------------|----------|
| **Connection refused** | Server not running | Start server with `./airmouse-server` |
| | Firewall blocking port | Open ports 8080, 8081, 8082 |
| | Wrong IP address | Verify IP with `ipconfig` / `ifconfig` |
| **WebSocket handshake fails** | Version mismatch | Ensure server version ≥ 3.0 |
| | Invalid token | Regenerate pairing QR code |
| **High latency** | Network congestion | Use Ethernet or 5GHz WiFi |
| | Server overload | Reduce client count or upgrade hardware |
| **Gestures not recognized** | Low confidence threshold | Lower threshold or retrain model |
| | Insufficient training data | Record 10+ samples per gesture |
| **Proximity not working** | Bluetooth disabled | Enable Bluetooth |
| | Wrong device paired | Verify MAC address in settings |
| | Calibration needed | Run calibration routine |
### Debugging Commands
```bash
# Check if server is running
curl http://localhost:8081/health
# Get server status
curl http://localhost:8081/api/status
# List connected devices
curl http://localhost:8081/api/devices
# Test WebSocket connection (using wscat)
npm install -g wscat
wscat -c ws://localhost:8081/ws
# Monitor UDP discovery
sudo tcpdump -i any port 8082 -n
# Check open ports
lsof -i :8080
lsof -i :8081
lsof -i :8082
```
### Logging
**Android Logcat:**
```bash
adb logcat -s ConnectionManager:V SensorService:V WebSocketManager:V
```
**Server Logs:**
```bash
tail -f ~/.config/airmouse/airmouse.log
```
---
## Version History
| Version | Date | Changes |
|---------|------|---------|
| 3.0.0 | 2025-01-15 | Initial protocol specification |
| | | Added WebSocket as primary transport |
| | | Added gesture recognition support |
| | | Added proximity lock/unlock |
| | | Added UDP discovery |
---
## Appendix
### A. Message Size Limits
| Message Type | Max Size (bytes) |
|--------------|------------------|
| `move` | 128 |
| `click` | 64 |
| `gesture` | 256 |
| `proximity` | 128 |
| `control` | 64 |
| `hello` | 256 |
### B. Recommended Sensor Rates
| Sensor | Recommended Rate | Purpose |
|--------|------------------|---------|
| Gyroscope | 100 Hz | Movement detection |
| Accelerometer | 100 Hz | Orientation detection |
| Rotation Vector | 60 Hz | Smooth orientation |
| Magnetometer | 20 Hz | Heading correction |
### C. Bluetooth RSSI to Distance Mapping (Approximate)
| RSSI (dBm) | Distance (meters) | Quality |
|------------|-------------------|---------|
| -30 to -40 | 0.2 - 0.5 | Excellent |
| -40 to -55 | 0.5 - 1.5 | Good |
| -55 to -65 | 1.5 - 3.0 | Fair |
| -65 to -75 | 3.0 - 5.0 | Poor |
| < -75 | > 5.0 | Very Poor |
---
**Document Version:** 1.0
**Last Updated:** 2025-01-15
**Protocol Version:** 3.0
**Maintainer:** Air Mouse Team <support@airmouse.io>

Xet Storage Details

Size:
43.2 kB
·
Xet hash:
23753db7bbcd68f004b09c0b08a1caa3e3c2bb0e153f357fab430173dfef3bc3

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.