- Architecture overview, BLE and WebSocket protocols - All 19 modules with command IDs validated against smali source - BLE packet format with CRC-16/MODBUS pseudocode - Complete WsCmd index (~300 commands) - Connection flow with pseudocode examples - Methodology section explaining APK decompilation process
141 lines
5.0 KiB
Markdown
141 lines
5.0 KiB
Markdown
# WebSocket Protocol
|
|
|
|
## Connection
|
|
|
|
After BLE authentication, the app connects via WebSocket for all telescope control.
|
|
|
|
```
|
|
URL: ws://<device_ip>:9900/?client_id=<client_id>
|
|
Port: 9900 (primary), 4409/4410 (secondary)
|
|
Scheme: ws:// (unencrypted, NOT wss://)
|
|
```
|
|
|
|
The device IP is obtained from `ResGetconfig.ip` (if already on WiFi) or `ResSta.ip` (after STA configuration).
|
|
|
|
The `client_id` is stored in MMKV under key `"data_default_client_id"`, or generated if not present.
|
|
|
|
Default device IP: `192.168.88.1`
|
|
|
|
## WsPacket Format
|
|
|
|
Every WebSocket message is a serialized `BaseProto.WsPacket` protobuf:
|
|
|
|
```protobuf
|
|
message WsPacket {
|
|
int32 majorVersion = 1; // Always 2
|
|
int32 minorVersion = 2; // Always 3
|
|
int32 deviceId = 3; // Target device ID (see DeviceType)
|
|
int32 moduleId = 4; // Module ID (0-18, see module table)
|
|
int32 cmd = 5; // Command ID (see WsCmd index)
|
|
int32 type = 6; // Message type: 0=request, 1=response, 2=notification, 3=reply
|
|
bytes data = 7; // Protobuf-encoded payload for the specific module
|
|
string clientId = 8; // App client identifier
|
|
}
|
|
```
|
|
|
|
### Pseudocode: Sending a Command
|
|
|
|
```python
|
|
import protobuf
|
|
|
|
def send_command(websocket, device_id, module_id, cmd, payload_bytes, client_id):
|
|
"""Send a command via WebSocket."""
|
|
packet = WsPacket(
|
|
majorVersion=2,
|
|
minorVersion=3,
|
|
deviceId=device_id,
|
|
moduleId=module_id,
|
|
cmd=cmd,
|
|
type=0, # request
|
|
data=payload_bytes,
|
|
clientId=client_id
|
|
)
|
|
websocket.send(packet.SerializeToString())
|
|
|
|
def send_track_start(websocket, device_id, client_id, x, y, w, h, cam_id):
|
|
"""Example: Start tracking."""
|
|
track_req = TrackProto.ReqStartTrack(x=x, y=y, w=w, h=h, camId=cam_id)
|
|
send_command(websocket, device_id, module_id=7, cmd=14800,
|
|
payload_bytes=track_req.SerializeToString(), client_id=client_id)
|
|
```
|
|
|
|
## Message Types
|
|
|
|
| type | Name | Description |
|
|
|------|------|-------------|
|
|
| 0 | request | App → Device command |
|
|
| 1 | response | Device → App response to a request |
|
|
| 2 | notification | Device → App spontaneous notification |
|
|
| 3 | reply | Device → App acknowledgement |
|
|
|
|
## Keepalive: DwarfPing / DwarfEcho
|
|
|
|
After WebSocket connection, the app periodically sends `DwarfPing` and the device responds with `DwarfEcho`.
|
|
|
|
```protobuf
|
|
message DwarfPing {
|
|
int32 vocaltype = 1; // VT_PING = 1
|
|
int64 timestamp = 2; // Unix timestamp
|
|
bytes magic = 3; // Session magic bytes
|
|
repeated DwarfPing vocals = 4;
|
|
repeated NifAP mutes = 5;
|
|
}
|
|
|
|
message DwarfEcho {
|
|
int32 vocaltype = 1; // VT_ECHO = 2
|
|
int64 timestamp = 2; // Unix timestamp
|
|
bytes magic = 3; // Session magic bytes
|
|
int64 tsPing = 4; // Echo of the ping timestamp
|
|
bytes macAddress = 5; // Device MAC address
|
|
BleProto model = 6; // Device model info
|
|
string sn = 7; // Serial number
|
|
string name = 8; // Device name
|
|
string psw = 9; // Password
|
|
string fwVersion = 10; // Firmware version
|
|
string wsScheme = 11; // WebSocket scheme ("ws")
|
|
int32 session = 12; // Session ID
|
|
BleProto ap = 13; // AP info
|
|
BleProto sta = 14; // STA info
|
|
}
|
|
```
|
|
|
|
> **Note**: DwarfEcho contains complete device info (firmware, MAC, SSID, IP, etc.).
|
|
|
|
## Response Routing
|
|
|
|
The client uses `WsRequestHandle` to dispatch responses:
|
|
|
|
1. Parse `WsPacket` from received bytes
|
|
2. Extract `cmd` (command ID)
|
|
3. Look up registered handlers in a `HashMap<Integer, List>` for this cmd
|
|
4. Execute callbacks with `WsPacket.getData()` (deserialized payload)
|
|
|
|
## Typical Exchange
|
|
|
|
```
|
|
App Device
|
|
│ │
|
|
│ WsPacket(type=0, moduleId=1, │
|
|
│ cmd=10000, data=ReqOpenCamera) │
|
|
│ ─────────────────────────────────────► │
|
|
│ │
|
|
│ WsPacket(type=1, cmd=10000, │
|
|
│ data=ComResponse{code=0}) │
|
|
│ ◄───────────────────────────────────── │
|
|
│ │
|
|
│ WsPacket(type=0, moduleId=7, │
|
|
│ cmd=14800, data=ReqStartTrack) │
|
|
│ ─────────────────────────────────────► │
|
|
│ │
|
|
│ WsPacket(type=2, cmd=15200, │
|
|
│ data=NotifyProto{...}) │
|
|
│ ◄───────────────────────────────────── │
|
|
│ (spontaneous notification) │
|
|
```
|
|
|
|
## Protocol Version
|
|
|
|
| Field | Value | Description |
|
|
|-------|-------|-------------|
|
|
| `WS_MAJOR_VERSION_NUMBER` | 2 | Current major version |
|
|
| `WS_MINOR_VERSION_NUMBER` | 3 | Current minor version | |