Fix BEE-ACCESS-PLAN: correct tunnel topology, remove wlp1s0f1 kill
This commit is contained in:
parent
a67247df68
commit
726241e1e8
1 changed files with 108 additions and 145 deletions
|
|
@ -3,201 +3,165 @@ _Updated 2026-03-22 — read this before touching the Bee_
|
|||
|
||||
---
|
||||
|
||||
## Network Topology (important)
|
||||
|
||||
```
|
||||
Cobb's phone ──── Bee AP (wlp1s0f0, 192.168.0.10) ──── phone gets 192.168.0.x
|
||||
ROUTING CONFLICT on phone
|
||||
(both AP and zerocool are 192.168.0.0/24)
|
||||
|
||||
Bee WiFi client (wlp1s0f1) ──── zerocool ──── Lucy (192.168.0.5) ──── OpenClaw
|
||||
```
|
||||
|
||||
**Key facts:**
|
||||
- sshd on Bee binds ONLY to `192.168.0.10` (AP interface) — confirmed from recon
|
||||
- The reverse tunnel OUTBOUND uses `wlp1s0f1` (zerocool) — do NOT kill this interface
|
||||
- Routing conflict is on Cobb's PHONE (both AP and zerocool are 192.168.0.0/24)
|
||||
- Killing wlp1s0f1 kills zerocool → kills the tunnel path → wrong
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Get Clean Access
|
||||
|
||||
**Physical requirement:** Be near the truck with your phone.
|
||||
### 1a. Phone connects to Bee AP
|
||||
Connect to `dashcam-4A928016A02C1046`, SSH to `root@192.168.0.10`
|
||||
|
||||
### 1a. Connect before zerocool does
|
||||
Boot the Bee and **immediately** connect your phone to `dashcam-4A928016A02C1046` before it associates with zerocool. If zerocool connects first, we get routing hell again.
|
||||
|
||||
### 1b. Set up reverse tunnel correctly
|
||||
From the Bee (via your phone SSH session on the AP):
|
||||
### 1b. Start reverse tunnel FROM THE BEE immediately
|
||||
Run this on the Bee before the routing conflict kicks you off:
|
||||
```bash
|
||||
ssh -R 2222:192.168.0.10:22 -N -o StrictHostKeyChecking=no root@192.168.0.5 &
|
||||
```
|
||||
> **Critical:** must be `192.168.0.10:22` not `localhost:22` — sshd only binds to the AP interface.
|
||||
- Goes OUTBOUND via wlp1s0f1 (zerocool) to Lucy
|
||||
- AP interface not involved in this path
|
||||
- Even if your phone SSH session dies, tunnel stays alive
|
||||
- Lucy will show `127.0.0.1:2222` listening
|
||||
|
||||
**Auth question to resolve:** What key does the Bee use to connect to Lucy? Either:
|
||||
- Check `/root/.ssh/` on the Bee for existing keys
|
||||
- Or add the Bee's pubkey to Lucy's `authorized_keys` during this session
|
||||
**Auth requirement:** Bee needs a key that Lucy's `root` authorized_keys accepts.
|
||||
- Check what's in `/root/.ssh/` on the Bee
|
||||
- If nothing: during the phone session, generate a key on Bee and add pubkey to Lucy's authorized_keys
|
||||
|
||||
### 1c. Verify tunnel from OpenClaw
|
||||
Once tunnel is up, I'll verify with:
|
||||
### 1c. Verify from OpenClaw
|
||||
```bash
|
||||
# Lucy should show port 2222 listening
|
||||
ss -tlnp | grep 2222
|
||||
ssh lucy "ss -tlnp | grep 2222"
|
||||
# Should show: LISTEN 0 128 127.0.0.1:2222
|
||||
```
|
||||
Then I connect via `127.0.0.1:2222` on Lucy.
|
||||
|
||||
### 1d. Optional: disconnect Bee from zerocool
|
||||
To avoid routing conflict entirely, kill the WiFi client connection while we work:
|
||||
```bash
|
||||
ip link set wlp1s0f1 down
|
||||
```
|
||||
Re-enable after: `ip link set wlp1s0f1 up`
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Read-Only Recon (NO WRITES)
|
||||
|
||||
Once I'm in via the tunnel, I run these in order. Read only.
|
||||
|
||||
### 2a. Storage inventory
|
||||
```bash
|
||||
df -h
|
||||
du -sh /data/recording/*/
|
||||
ls -la /data/recording/ml_metadata/ | head -20
|
||||
ls -la /data/recording/unprocessed_framekm/ | head -5
|
||||
sqlite3 /data/odc-api.db ".schema"
|
||||
sqlite3 /data/odc-api.db ".tables"
|
||||
sqlite3 /data/odc-api.db ".schema framekms"
|
||||
sqlite3 /data/odc-api.db "SELECT COUNT(*) FROM framekms;"
|
||||
sqlite3 /data/odc-api.db "SELECT * FROM framekms LIMIT 3;"
|
||||
ls /data/recording/ml_metadata/ | head -20
|
||||
cat $(ls /data/recording/ml_metadata/ | head -1) 2>/dev/null
|
||||
```
|
||||
**Goal:** Understand how much data is stored and in what state.
|
||||
|
||||
### 2b. Redis key scan (live detections)
|
||||
### 2b. Redis — find detection keys
|
||||
```bash
|
||||
redis-cli keys "*"
|
||||
redis-cli type GNSSFusion30Hz
|
||||
redis-cli zrevrange GNSSFusion30Hz 0 2
|
||||
# Look for detection/landmark keys map-ai publishes to:
|
||||
# Look specifically for detection/landmark keys:
|
||||
redis-cli keys "*landmark*"
|
||||
redis-cli keys "*detection*"
|
||||
redis-cli keys "*sign*"
|
||||
redis-cli keys "*map*"
|
||||
redis-cli keys "*ai*"
|
||||
# Check GNSSFusion30Hz (may not appear until Bee has been running a while):
|
||||
redis-cli type GNSSFusion30Hz 2>/dev/null
|
||||
redis-cli zrevrange GNSSFusion30Hz 0 2 2>/dev/null
|
||||
```
|
||||
**Goal:** Find the exact Redis key(s) map-ai writes detections to.
|
||||
|
||||
### 2c. Read odc-api source — find detection key
|
||||
### 2c. Find detection key in odc-api source
|
||||
```bash
|
||||
grep -i "landmark\|detection\|redis\|publish\|set\|zadd" /opt/odc-api/odc-api-bee.js | head -50
|
||||
grep -in "redis\|landmark\|detection\|zadd\|rpush\|publish" /opt/odc-api/odc-api-bee.js | head -40
|
||||
```
|
||||
**Goal:** Confirm exactly how odc-api reads detections from Redis so we know what key to poll.
|
||||
|
||||
### 2d. Read map-ai source — confirm write pattern
|
||||
### 2d. Find detection key in map-ai source
|
||||
```bash
|
||||
grep -i "redis\|set\|zadd\|publish\|landmark\|detection" /opt/map-ai/map-ai.py | head -50
|
||||
# Also check if there's a compiled version or if it's pure Python:
|
||||
ls /opt/map-ai/
|
||||
grep -in "redis\|landmark\|detection\|zadd\|rpush\|publish" /opt/map-ai/map-ai.py 2>/dev/null | head -40
|
||||
```
|
||||
**Goal:** Confirm what Redis key map-ai writes detections to after inference.
|
||||
|
||||
### 2e. Check ml_metadata contents
|
||||
```bash
|
||||
ls -la /data/recording/ml_metadata/ | tail -20
|
||||
# Look at a sample file:
|
||||
cat $(ls /data/recording/ml_metadata/ | head -1)
|
||||
```
|
||||
**Goal:** Understand if detection metadata is also written to disk files (backup to Redis).
|
||||
|
||||
### 2f. Check frame storage
|
||||
### 2e. Frame storage format
|
||||
```bash
|
||||
ls /tmp/recording/pics/ | head -5
|
||||
ls /tmp/recording/pics/ | wc -l
|
||||
# Filename format:
|
||||
ls /tmp/recording/pics/ | head -1
|
||||
```
|
||||
**Goal:** Confirm frame filename format for detection-to-image correlation.
|
||||
|
||||
### 2g. Check existing SSH keys on Bee
|
||||
### 2f. SSH keys on Bee
|
||||
```bash
|
||||
ls -la /home/root/.ssh/ 2>/dev/null || ls -la /root/.ssh/ 2>/dev/null
|
||||
ls -la /root/.ssh/ 2>/dev/null
|
||||
cat /root/.ssh/authorized_keys 2>/dev/null
|
||||
ls /root/.ssh/id_* 2>/dev/null
|
||||
```
|
||||
**Goal:** Know what keys exist for tunnel auth and for our post-liberation access.
|
||||
|
||||
### 2h. Check service file for map-ai dependency
|
||||
### 2g. map-ai service file
|
||||
```bash
|
||||
cat /lib/systemd/system/map-ai.service 2>/dev/null || \
|
||||
systemctl cat map-ai.service
|
||||
```
|
||||
**Goal:** Confirm the `Requires=odc-api.service` line so we know what to override in the drop-in.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Decisions Based on Recon
|
||||
|
||||
After recon, we decide:
|
||||
|
||||
### 3a. Detection key confirmed?
|
||||
- **Yes:** Write forwarder to poll that Redis key directly
|
||||
- **No Redis key found:** Use ml_metadata files OR keep polling odc-api endpoints (low frequency, not localhost)
|
||||
|
||||
### 3b. ml_metadata has useful files?
|
||||
- **Yes:** Primary source for detections — tail by mtime, parse directly
|
||||
- **No:** Redis is the only path
|
||||
|
||||
### 3c. How much data is stored?
|
||||
- Estimate backfill time/volume to ADAMaps
|
||||
- Decide if we do a one-time backfill before liberation or after
|
||||
| Finding | Decision |
|
||||
|---------|----------|
|
||||
| Detection Redis key found | Forwarder polls Redis directly |
|
||||
| No detection Redis key | Use ml_metadata files or poll odc-api at low frequency |
|
||||
| ml_metadata has detection files | Primary source, tail by mtime |
|
||||
| Large stored framekm backlog | Plan backfill to ADAMaps before liberation |
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Liberation Plan (v0.6)
|
||||
## Step 4 — Liberation (v0.6)
|
||||
|
||||
Based on recon findings, update `liberate-v0.5.sh` to `v0.6`:
|
||||
|
||||
### Kill list (services to stop + disable)
|
||||
### Kill list
|
||||
```
|
||||
hivemapper-data-logger ← the uploader, MUST kill
|
||||
mitmproxy ← Hivemapper proxy, MUST kill
|
||||
beekeeper-plugin ← Hivemapper telemetry/HW comms, kill
|
||||
here-plugin ← HERE Maps integration, kill
|
||||
mender-client ← OTA update client, kill (recovery via USB still works)
|
||||
odc-api ← Node.js REST layer, kill (we read from Redis/files directly)
|
||||
lte.service ← Kill LTE upload path (no SIM = irrelevant, but block anyway)
|
||||
hivemapper-data-logger ← MUST — the uploader
|
||||
mitmproxy ← MUST — Hivemapper proxy
|
||||
beekeeper-plugin ← kill — Hivemapper telemetry
|
||||
here-plugin ← kill — HERE Maps
|
||||
mender-client ← kill — OTA updates (USB recovery still works)
|
||||
odc-api ← kill — Node.js bloat (we read Redis/files directly)
|
||||
```
|
||||
|
||||
### Keep list (services that stay running)
|
||||
### Keep list
|
||||
```
|
||||
redis ← IPC backbone, keep
|
||||
depthai_gate ← Camera hardware init, keep
|
||||
map-ai ← ML inference (sign detection), keep ← THIS IS THE VALUE
|
||||
jpeg-recorder ← Frame storage, keep
|
||||
video-processor ← Frame pipeline, keep
|
||||
RedisHandler ← Sensor fusion, keep
|
||||
datalogger ← GPS/IMU logging, keep
|
||||
hostapd ← AP, keep (how we connect)
|
||||
dnsmasq ← DHCP on AP, keep
|
||||
redis ← IPC backbone
|
||||
depthai_gate ← Camera hardware init
|
||||
map-ai ← ML inference — THIS IS THE VALUE
|
||||
jpeg-recorder ← Frame storage
|
||||
video-processor ← Frame pipeline
|
||||
RedisHandler ← Sensor fusion
|
||||
datalogger ← GPS/IMU logging to SQLite
|
||||
hostapd / dnsmasq ← AP + DHCP
|
||||
```
|
||||
|
||||
### New service to install: adacam-forwarder (rewritten)
|
||||
### New service: adacam-forwarder (rewritten)
|
||||
- Polls detection Redis key for new entries
|
||||
- Grabs JPEG from `/tmp/recording/pics/` by timestamp
|
||||
- POSTs to ADAMaps `/api/ingest` + `/api/images`
|
||||
- Tracks state in `/data/adacam/forwarder-state.json`
|
||||
- Runs every 30s, pure Python, minimal CPU
|
||||
|
||||
Lightweight Python service that:
|
||||
1. Polls the detection Redis key (found in step 2b/2c) for new entries since last ID
|
||||
2. Grabs corresponding JPEG from `/tmp/recording/pics/` by timestamp match
|
||||
3. POSTs to ADAMaps `/api/ingest` with correct payload:
|
||||
```json
|
||||
{
|
||||
"device_id": "bee-{SERIAL}",
|
||||
"detections": [{
|
||||
"ts": 1709920000000,
|
||||
"lat": 34.05357,
|
||||
"lon": -118.24545,
|
||||
"class_label": "speed_limit_35",
|
||||
"overall_confidence": 0.88
|
||||
}]
|
||||
}
|
||||
```
|
||||
4. Uploads image via `POST /api/images` (multipart)
|
||||
5. Tracks last processed ID in `/data/adacam/forwarder-state.json`
|
||||
6. Runs every 30s — low overhead, no Node.js
|
||||
|
||||
### systemd drop-in for map-ai (removes odc-api dep)
|
||||
### systemd drop-in (removes odc-api dep from map-ai)
|
||||
```ini
|
||||
# /etc/systemd/system/map-ai.service.d/override.conf
|
||||
# /etc/systemd/system/map-ai.service.d/no-odc-api.conf
|
||||
[Unit]
|
||||
Requires=redis.service
|
||||
# Remove: Requires=odc-api.service
|
||||
# Overrides Requires=odc-api.service from base unit
|
||||
```
|
||||
|
||||
### SSH key installation
|
||||
Drop OpenClaw pubkey to `/root/.ssh/authorized_keys`:
|
||||
### SSH keys
|
||||
Drop to `/root/.ssh/authorized_keys`:
|
||||
```
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOQxwJU91TCxds34P18D3xRbu7rxlrgTUoml/H8nxeDK kayos@openclaw
|
||||
```
|
||||
|
||||
### Domain blocks (append to /etc/hosts)
|
||||
### Domain blocks (/etc/hosts)
|
||||
```
|
||||
0.0.0.0 data.api.hivemapper.com
|
||||
0.0.0.0 api.hivemapper.com
|
||||
|
|
@ -205,30 +169,26 @@ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOQxwJU91TCxds34P18D3xRbu7rxlrgTUoml/H8nxeDK
|
|||
0.0.0.0 direct.data.api.platform.here.com
|
||||
0.0.0.0 account.api.here.com
|
||||
0.0.0.0 mender.io
|
||||
0.0.0.0 s3.amazonaws.com
|
||||
```
|
||||
|
||||
### What we do NOT touch
|
||||
- `/etc/ssh/sshd_config` — no changes, password auth stays
|
||||
- AP config (`/var/hostapd.conf`) — no changes
|
||||
- IP (`192.168.0.10`) — stays forever
|
||||
- Firewall — no changes yet
|
||||
### Do NOT touch
|
||||
- `/etc/ssh/sshd_config`
|
||||
- AP config / SSID / IP
|
||||
- Firewall (no rules yet)
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Test Before Commit
|
||||
## Step 5 — Test
|
||||
|
||||
Before calling liberation complete:
|
||||
1. Verify `map-ai` still starts and `MAP_AI_READY` appears in Redis
|
||||
2. Verify our forwarder receives detections and posts successfully to ADAMaps
|
||||
3. Verify `depthai-device-kb` process still spawns (ML inference running)
|
||||
1. `redis-cli get MAP_AI_READY` → should be "True"
|
||||
2. Check forwarder log → detections posting to ADAMaps
|
||||
3. Verify no Hivemapper traffic (`nmap` or check `/etc/hosts` working)
|
||||
4. Check `/data/adacam/forwarder-state.json` updating
|
||||
5. Confirm no Hivemapper upload traffic (check hosts block is working)
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Build bee-tunnel.service (permanent tunnel)
|
||||
|
||||
After liberation, install a persistent reverse tunnel service so we never need physical access again:
|
||||
## Step 6 — bee-tunnel.service (permanent remote access)
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
|
|
@ -238,7 +198,8 @@ Wants=network-online.target
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/ssh -N -R 2222:192.168.0.10:22 \
|
||||
ExecStart=/usr/bin/ssh -N \
|
||||
-R 2222:192.168.0.10:22 \
|
||||
-o StrictHostKeyChecking=no \
|
||||
-o ServerAliveInterval=30 \
|
||||
-o ServerAliveCountMax=3 \
|
||||
|
|
@ -250,18 +211,20 @@ RestartSec=30
|
|||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
Goes outbound via wlp1s0f1 (zerocool) — AP interface not involved.
|
||||
|
||||
---
|
||||
|
||||
## Known Issues / Gotchas
|
||||
## Known Issues
|
||||
|
||||
| Issue | Notes |
|
||||
|-------|-------|
|
||||
| sshd binds to `192.168.0.10` only | Never use `localhost:22` in tunnel |
|
||||
| depthai-device-kb runs at 98% CPU | Normal — that's the VPU doing ML inference |
|
||||
| rngd at 20% CPU | Suspicious — investigate if it's needed |
|
||||
| Redis is localhost:6379 only | Need to be on Bee to query it |
|
||||
| GNSSFusion30Hz not in recon redis-keys | Recon was only 5min post-boot — key appears later |
|
||||
| map-ai Requires=odc-api in systemd | Must add drop-in override before killing odc-api |
|
||||
| ml_metadata limited to 20MB | Small — Redis is likely primary detection source |
|
||||
| Lots of unprocessed data on disk | Backfill to ADAMaps before or after liberation TBD |
|
||||
| sshd binds to 192.168.0.10 only | Reverse tunnel must use `192.168.0.10:22` not `localhost:22` |
|
||||
| Routing conflict on phone | AP + zerocool both 192.168.0.0/24 — start tunnel BEFORE conflict kicks you |
|
||||
| wlp1s0f1 must stay UP | It's the zerocool path — tunnel dies without it |
|
||||
| depthai-device-kb at 98% CPU | Normal — VPU running ML inference |
|
||||
| rngd at 20% CPU | Investigate — may be killable |
|
||||
| Redis localhost:6379 only | Must be on Bee or tunneled in to query |
|
||||
| GNSSFusion30Hz absent at boot | Appears after GNSS warms up (~5-10 min) |
|
||||
| Bee has stored framekm backlog | Plan backfill to ADAMaps |
|
||||
| Bee-to-Lucy auth key unknown | Resolve during first phone session |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue