archy/.claude/plans/polished-napping-squid.md
2026-03-17 00:03:08 +00:00

109 lines
4.9 KiB
Markdown

# Meshcore Mesh Networking — Phase 1 Implementation Plan
## Context
Adding mesh networking to Archipelago using Heltec V3 devices running Meshcore firmware (Companion USB). Two nodes (.228 and .198) will exchange encrypted identity and text messages over LoRa radio with no internet required. The existing `mesh.rs` wraps the Meshtastic CLI — this replaces it with a native Meshcore serial protocol driver.
## Architecture
Convert `mesh.rs` into `mesh/` module directory:
```
core/archipelago/src/mesh/
├── mod.rs — Public API, MeshService, config (migrated from mesh.rs)
├── types.rs — MeshPeer, MeshMessage, MeshStatus, DeviceType
├── protocol.rs — Meshcore binary frame protocol (encode/decode/commands)
├── serial.rs — MeshcoreDevice: async serial driver (serial2-tokio)
├── crypto.rs — X25519 ECDH + ChaCha20-Poly1305 per-message encryption
└── listener.rs — Background tokio task: serial reader + message dispatcher
```
Frontend:
```
neode-ui/src/stores/mesh.ts — Pinia store
neode-ui/src/views/Mesh.vue — Mesh status, peers, messaging UI
```
## Dependency
Add to `core/archipelago/Cargo.toml`:
```toml
serial2-tokio = "0.1"
```
All crypto deps already present (chacha20poly1305, ed25519-dalek, curve25519-dalek).
## Meshcore Protocol Summary
- **Frame format**: `>` + 2-byte LE length + data (outbound), `<` + 2-byte LE length + data (inbound)
- **Baud**: 115200, 8N1
- **Max message**: 160 bytes
- **Init sequence**: CMD_DEVICE_QUERY (0x16) -> CMD_APP_START (0x01) -> CMD_SET_DEVICE_TIME (0x06)
- **Key commands**: SEND_TXT_MSG (0x02), SEND_CHANNEL_TXT_MSG (0x03), GET_CONTACTS (0x04), SYNC_NEXT_MESSAGE (0x0A), SEND_SELF_ADVERT (0x07)
- **Push events** (async, >=0x80): NEW_CONTACT (0x8A), ACK (0x82), MESSAGES_WAITING (0x83)
## Encryption Design
Reuses existing identity.rs X25519 key agreement:
1. Nodes broadcast identity on mesh channel: `ARCHY:1:{did}:{ed25519_pubkey}:{x25519_pubkey}`
2. Receiving node derives shared secret: X25519(our_secret, their_x25519_pub)
3. All DMs encrypted: ChaCha20-Poly1305 with random 12-byte nonce
4. Wire format: [nonce 12B] + [ciphertext] + [tag 16B] — fits in 160B limit for ~130B plaintext
## RPC Endpoints
| Method | Action |
|--------|--------|
| `mesh.status` | Device + mesh status (updated) |
| `mesh.peers` | **NEW** — list discovered mesh peers |
| `mesh.messages` | **NEW** — get message history (last 100) |
| `mesh.send` | **NEW** — send encrypted message to peer |
| `mesh.broadcast` | Broadcast identity (updated for Meshcore) |
| `mesh.configure` | Update config (updated) |
## Implementation Steps
1. **Create mesh/ module, migrate existing code** — types.rs + mod.rs from mesh.rs
2. **protocol.rs** — Binary frame encode/decode, command builders, response parsers + unit tests
3. **crypto.rs** — X25519 ECDH + ChaCha20-Poly1305 encrypt/decrypt + unit tests
4. **serial.rs** — MeshcoreDevice with open/init/send/recv + device auto-detection
5. **listener.rs** — Background task: serial reader, peer cache, message store, reconnect
6. **mod.rs MeshService** — Wraps listener + config, start/stop lifecycle
7. **Update RPC handlers** — New endpoints, wire MeshService into RpcHandler
8. **Update RPC dispatch** — Add routes in mod.rs ~line 622
9. **Frontend store + view** — mesh.ts Pinia store, Mesh.vue with glass-card UI, router + nav
10. **Deploy + test** — Deploy to .228 and .198, plug in Heltec V3s, test end-to-end
## Key Files to Modify
- `core/archipelago/src/mesh.rs` -> delete, replace with `mesh/` directory
- `core/archipelago/src/api/rpc/mesh.rs` — update handlers
- `core/archipelago/src/api/rpc/mod.rs` — add routes (~line 622)
- `core/archipelago/Cargo.toml` — add serial2-tokio
- `neode-ui/src/router/index.ts` — add /dashboard/mesh route
- `neode-ui/src/views/Dashboard.vue` — add Mesh nav item
## Reusable Existing Code
- `identity.rs` lines 140-152: Ed25519 -> X25519 conversion (CompressedEdwardsY -> Montgomery)
- `identity.rs` `pubkey_bytes_from_did_key()`: extract raw pubkey from DID string
- `node_message.rs` pattern: IncomingMessage store with max 100 circular buffer
- `mesh.rs` `MeshConfig` + `load_config`/`save_config`: migrate directly into mod.rs
- `mesh.rs` `detect_meshtastic_devices()`: keep as fallback, add Meshcore probe-based detection
## Prerequisites
- Flash both Heltec V3 with Meshcore **Companion USB** role
- Add `archipelago` user to `dialout` group: `usermod -aG dialout archipelago`
- Connect Heltec V3 to USB on .228 and .198
## Verification
1. `cargo clippy --all-targets` passes with zero warnings
2. Unit tests pass: protocol encode/decode, crypto encrypt/decrypt roundtrip
3. Device detected on /dev/ttyUSB0 or /dev/ttyACM0
4. Init handshake completes (visible in tracing logs)
5. Identity broadcast from .228, received on .198
6. Encrypted DM sent .228 -> .198, decrypted and visible in UI
7. Mesh.vue shows device status, peer list, message history