Command Protocol
SmartPot uses a bidirectional LoRa command protocol between the base station and individual smart buoys. All packets are AES-128 encrypted. Every critical command requires an acknowledgment handshake confirming receipt and execution.
Packet Structure
Section titled “Packet Structure”flowchart LR
P["Preamble\n2 bytes"]
ID["Pot ID\n2 bytes"]
CMD["Cmd\n1 byte"]
PL["Payload\n0–24 bytes"]
SEQ["Seq\n2 bytes"]
MAC["CMAC\n4 bytes"]
P --> ID --> CMD --> PL --> SEQ --> MAC
style P fill:#e6f3f0,stroke:#2d7d6f
style ID fill:#e6f3f0,stroke:#2d7d6f
style CMD fill:#e8f0f5,stroke:#3a6d8c
style PL fill:#f0f4f8,stroke:#4a6785
style SEQ fill:#e8f0f5,stroke:#3a6d8c
style MAC fill:#e6f3f0,stroke:#2d7d6f
| Field | Size | Description |
|---|---|---|
| Preamble | 2 bytes | 0x5350 (“SP” for SmartPot) |
| Pot ID | 2 bytes | Unique trap identifier (0x0001–0xFFFE) |
| Command | 1 byte | Command opcode |
| Payload | 0–24 bytes | Command-specific data |
| Sequence | 2 bytes | Monotonic counter for replay protection |
| CMAC | 4 bytes | AES-CMAC truncated authentication tag |
Command Set
Section titled “Command Set”Downstream (Base → Buoy → Trap)
Section titled “Downstream (Base → Buoy → Trap)”| Opcode | Name | Payload | Description |
|---|---|---|---|
0x01 | LOCK_DOOR | — | Lock the servo-driven door latch to retain catch |
0x02 | UNLOCK_DOOR | — | Unlock door to release contents |
0x03 | SURFACE | — | Trigger ballast release for ropeless recovery |
0x04 | CAPTURE | — | Request on-demand image from trap camera |
0x05 | STATUS | — | Force immediate telemetry report |
0x06 | SLEEP | duration_hours (2B) | Enter deep hibernation |
0x07 | SET_MODE | mode (1B) | Set classification mode (0=auto, 1=manual, 2=log-only) |
0x08 | REBOOT | — | Soft restart both submerged unit and buoy |
Upstream (Trap → Buoy → Base)
Section titled “Upstream (Trap → Buoy → Base)”| Opcode | Name | Payload | Description |
|---|---|---|---|
0x80 | ACK | cmd_acked (1B) + status (1B) | Command acknowledgment |
0x81 | TELEMETRY | See Telemetry Format | Periodic status report |
0x82 | CATCH_EVENT | species (1B) + size_mm (2B) + action (1B) | Classification result |
0x83 | ALERT | alert_type (1B) + data (4B) | Drift, low battery, or fault alert |
0x84 | IMAGE_READY | chunk_count (1B) + total_bytes (2B) | Image available for download |
Acknowledgment Protocol
Section titled “Acknowledgment Protocol”Critical commands (LOCK_DOOR, UNLOCK_DOOR, SURFACE) use a three-phase handshake:
sequenceDiagram
participant Base as Base Station
participant Buoy as Smart Buoy
participant Trap as Submerged Unit
Base->>Buoy: Command (seq=N)
Buoy-->>Base: ACK (status=0x01, received)
Buoy->>Trap: Forward over tether
Trap-->>Buoy: Execution result
Buoy-->>Base: ACK (status=0x02, confirmed)
Note over Base: 10s timeout per attempt
Note over Base: 3 retries max
If no ACK is received within 10 seconds, the base retransmits up to 3 times using the same sequence number. After 3 failures, the command is marked as failed and the operator is alerted.
Image Transfer Protocol
Section titled “Image Transfer Protocol”The CAPTURE command triggers an on-demand image from the trap camera. The resulting image is delivered using a progressive JPEG transfer protocol — the same protocol used by the ESP32-CAM project.
Why Progressive JPEG
Section titled “Why Progressive JPEG”Standard JPEG files must be received in full before rendering. Progressive JPEGs encode the image in successive scans — a blurry full-frame preview arrives in the first few fragments, with each subsequent scan adding detail. Over a slow LoRa link (~686 bytes/sec), this means the operator sees a usable preview in seconds rather than waiting minutes for the full image.
Transfer Flow
Section titled “Transfer Flow”sequenceDiagram
participant Base as Base Station
participant Buoy as Smart Buoy
participant Trap as Submerged Unit
Base->>Buoy: CAPTURE (0x04)
Buoy-->>Base: ACK (received)
Buoy->>Trap: Forward over tether
Trap-->>Buoy: IMAGE_READY (0x84)<br/>chunk_count + total_bytes
Buoy-->>Base: IMAGE_READY relay
loop Scan-by-scan delivery
Trap->>Buoy: Image fragments (8-fragment windows)
Buoy->>Base: LoRa relay (168 raw bytes/fragment)
Base-->>Buoy: Window ACK bitmap
Buoy-->>Trap: ACK relay
end
Note over Base: Each scan = renderable preview
Protocol Details
Section titled “Protocol Details”| Parameter | Value |
|---|---|
| Fragment payload | 168 bytes raw JPEG data |
| Window size | 8 fragments |
| ACK timeout | 5 seconds per window |
| Max retries | 3 per window |
| Inter-packet delay | 50ms |
| Integrity | CRC8-CCITT per fragment, CRC16-CCITT full image |
For the complete protocol specification — including binary header format, segment indexing, NACK handling, and scan-level flags — see the Transfer Protocol reference.
Security
Section titled “Security”- AES-128-CMAC authentication on every packet
- Sequence counter prevents replay attacks
- Per-pot keys — compromise of one pot doesn’t affect the fleet
- Key provisioning happens during initial flash (see Encryption)