adacam/docs/BEE_DATA_PIPELINE.md

59 KiB

Hivemapper Bee → ADAMaps Data Pipeline

Complete data flow documentation for liberating Hivemapper Bee dashcams to ADAMaps Last Updated: 2026-03-22


Executive Summary

The Hivemapper Bee is an Intel Keem Bay-based dashcam with on-device AI detection. This document maps the complete data pipeline from camera capture to ADAMaps storage, identifying interception points for data liberation.

Key Insight: Detections are stored in /data/recording/landmarks/ files, NOT in SQLite. The SQLite database only contains sensor data (GPS, IMU, magnetometer).


System Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              HIVEMAPPER BEE HARDWARE                                 │
│                                                                                      │
│  ┌─────────────┐      ┌───────────────┐      ┌──────────────┐                       │
│  │  OV10640    │      │  Intel Keem   │      │   WiFi       │                       │
│  │  Camera     │ ───▶ │  Bay VPU      │      │   wlp1s0f0   │◀──▶ AP (192.168.0.10) │
│  │  2028x1024  │      │  (Myriad X)   │      │   wlp1s0f1   │◀──▶ Client (zerocool) │
│  └─────────────┘      └───────────────┘      └──────────────┘                       │
│                              │                       │                               │
│                              │                       │                               │
│                       ┌──────▼──────┐         ┌──────▼──────┐                       │
│                       │    ARM      │         │    LTE      │                       │
│                       │  Cortex-A53 │         │   Modem     │                       │
│                       │   (4 core)  │         │  (Optional) │                       │
│                       └─────────────┘         └─────────────┘                       │
└─────────────────────────────────────────────────────────────────────────────────────┘

1. Camera Capture Pipeline

Service: depthai_gate

Path:     /usr/bin/depthai_gate
Config:   systemd (no external config file)
Logs:     journald
PID:      666 (typical process list)
CPU:      ~1% idle, ~98% inference

systemd Unit:

[Unit]
Description=DepthAI Gate
StartLimitIntervalSec=600
StartLimitBurst=40

[Service]
ExecStart=/usr/bin/depthai_gate
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

VPU Inference Architecture

┌──────────────────────────────────────────────────────────────────────────────┐
│                          DEPTHAI_GATE SERVICE                                 │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│  ┌─────────────┐     ┌──────────────┐     ┌─────────────────────────────┐   │
│  │   Camera    │     │  DepthAI     │     │    Intel Keem Bay VPU       │   │
│  │  OV10640    │────▶│  Pipeline    │────▶│  (16 SHAVE cores via NCE)   │   │
│  │  2028x1024  │     │  Manager     │     │                             │   │
│  └─────────────┘     └──────────────┘     │  ┌─────────────────────┐   │   │
│                                            │  │ model.blob          │   │   │
│                                            │  │ (OpenVINO compiled) │   │   │
│                                            │  │ ~6MB, YOLOv8-nano   │   │   │
│                                            │  └─────────────────────┘   │   │
│                                            └─────────────────────────────┘   │
│                                                         │                     │
│                                                         ▼                     │
│  ┌─────────────────────────────────────────────────────────────────────┐     │
│  │                      OUTPUT STREAMS                                  │     │
│  │                                                                      │     │
│  │   Raw Frames ─────────▶ /tmp/recording/pics/                        │     │
│  │   Detection Boxes ────▶ Redis (via IPC)                             │     │
│  │   Encoded Video ──────▶ video-processor                             │     │
│  └─────────────────────────────────────────────────────────────────────┘     │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

Frame Capture Output

Path:    /tmp/recording/pics/
Format:  {timestamp_ms}_{frame_id}_{sequence}.jpg
Example: 1744153672750_858894_001.jpg
         └──────┬─────┘ └──┬──┘ └┬┘
              unix_ms   frame#  seq
              
Retention: Managed by hivemapper-folder-purger (8GB limit)
Resolution: 2028x1024 @ 30fps
Encoding: JPEG (via VAAPI hardware encoder)

VPU Firmware Location

/tmp/gate_fw_o2n73qwp/{hash}/
├── depthai-device-kb           # VPU device binary (98% CPU during inference)
├── depthai-gate-stdout.log     # Service output
└── resources/
    └── depthai-vpu-fw-*.bin    # VPU firmware blob

2. AI Detection Pipeline

Service: map-ai

Path:     /opt/map-ai/map-ai.sh (wrapper)
          /opt/map-ai/map-ai.py (main Python script)
Config:   Reads from Redis, SQLite config
Logs:     /data/recording/map-ai.log
CPU:      ~28% (Python inference post-processing)

systemd Unit:

[Unit]
Description=map-AI
Requires=odc-api.service      # ← CRITICAL: This dependency must be removed
Requires=redis.service

[Service]
ExecStart=/opt/map-ai/map-ai.sh
ExecStartPost=-/usr/bin/redis-cli SET MAP_AI_READY "False"
ExecStopPost=-/usr/bin/redis-cli SET MAP_AI_READY "False"
Restart=always
RestartSec=5s
StandardOutput=append:/data/recording/map-ai.log
StandardError=append:/data/recording/map-ai.log

[Install]
WantedBy=multi-user.target

Detection Pipeline Architecture

┌──────────────────────────────────────────────────────────────────────────────┐
│                            MAP-AI SERVICE                                     │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   ┌────────────────┐    ┌─────────────────┐    ┌──────────────────┐         │
│   │  depthai_gate  │───▶│  Frame Buffer   │───▶│  LocateLandmark  │         │
│   │  (VPU output)  │    │  (Redis queue)  │    │  Node            │         │
│   └────────────────┘    └─────────────────┘    └────────┬─────────┘         │
│                                                          │                   │
│                                                          ▼                   │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                     DETECTION PROCESSING                             │   │
│   │                                                                      │   │
│   │  Input:  Raw detection boxes from VPU                               │   │
│   │          GPS/IMU data from Redis                                    │   │
│   │                                                                      │   │
│   │  Process:                                                           │   │
│   │    1. NMS (Non-Maximum Suppression)                                 │   │
│   │    2. Confidence thresholding (min 0.3)                             │   │
│   │    3. GPS fusion (attach lat/lon to detections)                     │   │
│   │    4. Temporal tracking (link same objects across frames)          │   │
│   │                                                                      │   │
│   │  Output: Landmark observations with:                                │   │
│   │    - class_label (road_sign, lane_marking, etc.)                   │   │
│   │    - overall_confidence (0.0-1.0)                                   │   │
│   │    - lat, lon (from GPS fusion)                                     │   │
│   │    - timestamp (unix_ms)                                            │   │
│   │    - bounding_box (x1, y1, x2, y2)                                  │   │
│   │    - observation_images (cropped chips)                             │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                          │                   │
│                                                          ▼                   │
│   ┌──────────────────┐                    ┌──────────────────────┐         │
│   │ StoreLandmarks   │───────────────────▶│  /data/recording/    │         │
│   │ Node             │                    │  landmarks/          │         │
│   └────────┬─────────┘                    └──────────────────────┘         │
│            │                                                                 │
│            ▼                                                                 │
│   ┌──────────────────┐                                                      │
│   │  Redis (ephemeral)│◀─── Detection events published here                │
│   └──────────────────┘                                                      │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

Detected Object Classes

Based on the OpenVINO model (YOLOv8-nano variant):

Class Label Description
0 road_sign Traffic signs (stop, yield, speed limit, etc.)
1 lane_marking Road lines, arrows, symbols
2 traffic_light Traffic signal heads
3 face Privacy detection (for blurring)
4 license_plate Privacy detection (for blurring)
5 road_marker Mile markers, reflectors
6 construction Construction signs/barriers
7 vegetation Overgrown vegetation blocking signs

Confidence Scores

# Typical thresholds (from map-ai.py)
MIN_DETECTION_CONFIDENCE = 0.3    # Minimum to store
PRIVACY_BLUR_THRESHOLD   = 0.5    # When to blur faces/plates
HIGH_CONFIDENCE          = 0.8    # Likely true positive

3. Data Storage on Bee

Directory Structure

/data/recording/
├── landmarks/              # Detection files (1.7MB observed)
│   ├── {timestamp}_*.json  # Individual landmark observations
│   └── ...
├── framekm/                # Compressed video bundles
│   ├── {bundle}.tar.gz
│   └── ...
├── unprocessed_framekm/    # Pending processing (8GB limit)
├── metadata/               # GPS/IMU session data
├── ml_metadata/            # ML inference metadata (20MB limit)
├── gps/                    # Raw GPS logs (200MB limit)
├── imu/                    # Raw IMU logs (360MB limit)
├── raw/                    # Raw sensor data (5MB limit)
├── cached_observations/    # Landmark observation images (cropped chips)
├── plugin_cache/           # Plugin data (500MB limit)
├── odc-api.log            # Node.js API logs
├── map-ai.log             # Python ML logs
├── video-processor.log    # Video encoding logs
└── redis-handler.log      # Sensor fusion logs

Landmark File Format

Location: /data/recording/landmarks/
Pattern:  {timestamp_ms}_{observation_id}.json

Example File Content:
{
  "id": 2945056,
  "class_label": "road_sign",
  "overall_confidence": 0.847,
  "lat": 33.841234,
  "lon": -118.391234,
  "timestamp": 1746377552043,
  "bounding_box": {
    "x1": 1234,
    "y1": 456,
    "x2": 1456,
    "y2": 678
  },
  "image_path": "/data/recording/cached_observations/1746377552_043000_2945056.jpg",
  "speed_mph": 35.2,
  "heading_deg": 127.4,
  "hdop": 1.2,
  "num_satellites": 12
}

FrameKM Bundle Format

/data/recording/framekm/{bundle_name}.tar.gz
├── frames/
│   ├── frame_001.jpg
│   ├── frame_002.jpg
│   └── ...
├── metadata.json          # Bundle metadata
├── gnss.json              # GPS track for bundle
└── imu.json               # IMU data for bundle

SQLite Schema: odc-api.db

-- Location: /data/odc-api.db

-- GPS/GNSS data (30Hz)
CREATE TABLE gnss (
    rowid       INTEGER PRIMARY KEY,
    lat_deg     REAL,
    lon_deg     REAL,
    alt_m       REAL,
    speed_mps   REAL,
    heading_deg REAL,
    hdop        REAL,
    num_satellites INTEGER,
    fix_type    INTEGER,
    unix_ms     INTEGER
);

-- GPS authentication data
CREATE TABLE gnss_auth (
    rowid       INTEGER PRIMARY KEY,
    auth_data   BLOB,
    unix_ms     INTEGER
);

-- IMU data (10Hz)
CREATE TABLE imu (
    rowid       INTEGER PRIMARY KEY,
    accel_x     REAL,
    accel_y     REAL,
    accel_z     REAL,
    gyro_x      REAL,
    gyro_y      REAL,
    gyro_z      REAL,
    unix_ms     INTEGER
);

-- Magnetometer data
CREATE TABLE magnetometer (
    rowid       INTEGER PRIMARY KEY,
    mag_x       REAL,
    mag_y       REAL,
    mag_z       REAL,
    unix_ms     INTEGER
);

-- FrameKM metadata
CREATE TABLE framekms (
    rowid       INTEGER PRIMARY KEY,
    name        TEXT,
    start_ms    INTEGER,
    end_ms      INTEGER,
    frame_count INTEGER,
    size_bytes  INTEGER,
    uploaded    INTEGER DEFAULT 0
);

-- Configuration
CREATE TABLE config (
    key         TEXT PRIMARY KEY,
    value       TEXT
);

-- Service state
CREATE TABLE state (
    service     TEXT PRIMARY KEY,
    healthy     INTEGER,
    last_update INTEGER
);

-- NOTE: NO landmarks/detections table!
-- Detections are stored in files, not SQLite

Redis Keys and Purposes

┌─────────────────────────┬─────────┬──────────────────────────────────────────┐
│ Key                     │ Type    │ Purpose                                  │
├─────────────────────────┼─────────┼──────────────────────────────────────────┤
│ MAP_AI_READY            │ string  │ "True" when inference active             │
│ GNSSFusion30Hz          │ zset    │ 30Hz GPS: lat/lon/alt/speed/hdop         │
│ ImuFusion10Hz           │ zset    │ 10Hz IMU: accel/gyro vectors             │
│ MagnetometerData        │ list    │ Magnetometer readings                    │
│ GnssFreqHz              │ string  │ Current GPS update frequency             │
│ LTE_INIT_IMEISV         │ string  │ LTE modem IMEISV                         │
│ LTE_INIT_IMEI           │ string  │ LTE modem IMEI                           │
│ REDIS_HANDLER_SESSION_ID│ string  │ Current session identifier               │
└─────────────────────────┴─────────┴──────────────────────────────────────────┘

GNSSFusion30Hz Entry Format:

{
  "lat_deg": 33.841234,
  "lon_deg": -118.391234,
  "alt_m": 45.2,
  "speed_mps": 15.7,
  "heading_deg": 127.4,
  "hdop": 1.2,
  "num_satellites": 12,
  "unix_milliseconds": 1746377552043
}

4. odc-api Service

Service Details

Path:    /opt/odc-api/odc-api-bee.js
Runtime: Node.js
Port:    5000
Logs:    /data/recording/odc-api.log
CPU:     ~14% (high for a REST API)
Memory:  ~144MB RSS

systemd Unit:

[Unit]
Description=ODC-API

[Service]
ExecStart=node /opt/odc-api/odc-api-bee.js
Restart=always
RestartSec=5s
StandardOutput=append:/data/recording/odc-api.log
StandardError=append:/data/recording/odc-api.log
Environment="ODC_VERSION=5.7.88"

[Install]
WantedBy=multi-user.target

REST API Architecture

┌──────────────────────────────────────────────────────────────────────────────┐
│                           ODC-API SERVICE (Port 5000)                         │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   External Request                                                            │
│        │                                                                      │
│        ▼                                                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    EXPRESS.JS ROUTER                                 │   │
│   │                                                                      │   │
│   │  /api/1/config/*     →  Config management                           │   │
│   │  /api/1/db/*         →  SQLite queries                              │   │
│   │  /api/1/gps/*        →  GPS data access                             │   │
│   │  /api/1/recordings/* →  Frame access                                │   │
│   │  /api/1/framekm/*    →  FrameKM bundles                             │   │
│   │  /api/1/cache/*      →  Data caching                                │   │
│   │  /api/landmarks/*    →  Landmark detection access                    │   │
│   │  /api/1/upload/*     →  Model/plugin upload                         │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│        │                            │                            │           │
│        ▼                            ▼                            ▼           │
│   ┌──────────┐              ┌──────────────┐            ┌──────────────┐    │
│   │  Redis   │              │   SQLite     │            │  Filesystem  │    │
│   │  Client  │              │  odc-api.db  │            │  /data/...   │    │
│   └──────────┘              └──────────────┘            └──────────────┘    │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

Landmark API Endpoints

# Get N most recent landmarks
GET http://192.168.0.10:5000/api/landmarks/n/{count}
→ Returns: Array of landmark objects

# Get landmarks since ID
GET http://192.168.0.10:5000/api/landmarks/from/{id}
→ Returns: Landmarks with id > {id}

# Get landmark images
GET http://192.168.0.10:5000/landmarks/images/{landmark_id}
→ Returns: Array of image file paths

# Get landmark bounding box
GET http://192.168.0.10:5000/landmarks/boundingBox/{landmark_id}
→ Returns: {boundingBox: {x1, y1, x2, y2}, chip_id}

Data Flow: How odc-api Reads Landmarks

Request: GET /api/landmarks/n/100
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  odc-api reads from:                            │
│                                                 │
│  1. /data/recording/landmarks/*.json            │
│     (Primary source - file-based)               │
│                                                 │
│  2. Redis ephemeral cache                       │
│     (For real-time streaming)                   │
│                                                 │
│  3. In-memory LRU cache                         │
│     (For repeated queries)                      │
└─────────────────────────────────────────────────┘
                  │
                  ▼
         JSON Response to Client

5. Data Egress (Liberation)

Current Hivemapper Upload Path (TO BLOCK)

┌───────────────────────────────────────────────────────────────────────────────┐
│                    HIVEMAPPER DATA EXFILTRATION                                │
│                                                                                │
│   ┌───────────┐     ┌──────────────┐     ┌─────────────────────────────────┐ │
│   │ map-ai    │────▶│ odc-api      │────▶│ mitmproxy (localhost:8888)      │ │
│   │           │     │ (port 5000)  │     │ rewrite_to_cloudflare.py        │ │
│   └───────────┘     └──────────────┘     └─────────────┬───────────────────┘ │
│                                                         │                     │
│   ┌───────────┐                                         ▼                     │
│   │hivemapper │     ┌──────────────┐     ┌─────────────────────────────────┐ │
│   │-data-     │────▶│ beekeeper-   │────▶│ HIVEMAPPER CLOUD                │ │
│   │ logger    │     │ plugin       │     │ api.hivemapper.com              │ │
│   └───────────┘     └──────────────┘     │ beemaps.com                     │ │
│                                          │ s3.hivemapper.com               │ │
│                                          └─────────────────────────────────┘ │
│                                                                                │
│   Services to KILL:                                                           │
│   - odc-api.service           (Node.js API - can replace with file read)     │
│   - mitmproxy.service         (Proxy to Cloudflare)                          │
│   - beekeeper-plugin.service  (Hivemapper control plane)                      │
│   - hivemapper-data-logger    (Binary data uploader)                         │
│   - mender-client.service     (OTA updates - blocks liberation)               │
│   - here-plugin.service       (HERE Maps integration)                        │
│   - model-zoo.service         (Model updates from Hivemapper)                │
│                                                                                │
│   Domains to BLOCK in /etc/hosts:                                             │
│   - hivemapper.com, api.hivemapper.com                                        │
│   - beemaps.com, api.trybeekeeper.ai                                         │
│   - docker.mender.io, s3.mender.io                                           │
│   - direct.data.api.platform.here.com                                        │
│   - dashcam-firmware.s3.us-west-2.amazonaws.com                              │
│   - cfapi.cloudflare.com                                                     │
│                                                                                │
└───────────────────────────────────────────────────────────────────────────────┘

New ADAMaps Upload Path (TO CREATE)

┌───────────────────────────────────────────────────────────────────────────────┐
│                       ADAMAPS DATA LIBERATION                                  │
│                                                                                │
│   ┌──────────────────────────────────────────────────────────────────────┐   │
│   │                  SERVICES TO KEEP                                     │   │
│   │                                                                       │   │
│   │  depthai_gate.service     - Camera capture & VPU inference           │   │
│   │  map-ai.service           - Detection processing (mod service file)  │   │
│   │  redis.service            - Sensor data store                        │   │
│   │  redis-handler.service    - Sensor fusion                           │   │
│   │  jpeg-recorder.service    - (optional) Raw frame capture             │   │
│   └──────────────────────────────────────────────────────────────────────┘   │
│                          │                                                    │
│                          ▼                                                    │
│   ┌──────────────────────────────────────────────────────────────────────┐   │
│   │                 ADACAM SERVICES (NEW)                                 │   │
│   │                                                                       │   │
│   │  ┌─────────────────────────┐    ┌────────────────────────────────┐  │   │
│   │  │ adacam-forwarder.service│    │ bee-agent-api.service          │  │   │
│   │  │                         │    │                                 │  │   │
│   │  │ Reads:                  │    │ Provides:                       │  │   │
│   │  │ - /data/recording/      │    │ - /status (health check)        │  │   │
│   │  │   landmarks/*.json      │    │ - /shell (remote commands)     │  │   │
│   │  │ - Redis GNSSFusion30Hz  │    │ - /landmarks (detection query) │  │   │
│   │  │                         │    │ - /redis (key inspection)       │  │   │
│   │  │ Writes:                 │    │                                 │  │   │
│   │  │ - POST to ADAMaps       │    │ Port: 8080                      │  │   │
│   │  │   /api/ingest           │    │ Auth: X-Agent-Key header        │  │   │
│   │  └────────────┬────────────┘    └────────────────────────────────┘  │   │
│   │               │                                                      │   │
│   └───────────────│──────────────────────────────────────────────────────┘   │
│                   │                                                           │
│                   ▼                                                           │
│   ┌──────────────────────────────────────────────────────────────────────┐   │
│   │                    BEE-TUNNEL SERVICE                                 │   │
│   │                                                                       │   │
│   │  SSH reverse tunnel: Bee → Lucy → OpenClaw/ADAMaps                   │   │
│   │                                                                       │   │
│   │  ExecStart=/usr/bin/ssh -i /data/ssh/bee_tunnel_key                  │   │
│   │            -R 2222:127.0.0.1:22                                      │   │
│   │            -N -o ServerAliveInterval=30                              │   │
│   │            -o StrictHostKeyChecking=no                               │   │
│   │            root@192.168.0.5                                          │   │
│   │                                                                       │   │
│   │  NOTE: Must bind to 127.0.0.1:22 NOT 192.168.0.10:22                │   │
│   │        (Hairpin AP routing breaks 192.168.0.10 target)              │   │
│   └──────────────────────────────────────────────────────────────────────┘   │
│                   │                                                           │
│                   ▼                                                           │
│   ┌──────────────────────────────────────────────────────────────────────┐   │
│   │                    ADAMAPS INGEST (Cloud/Self-Hosted)                 │   │
│   │                                                                       │   │
│   │  Endpoint: https://api.adamaps.org/api/ingest                        │   │
│   │  Auth:     X-AdaMaps-Key: adamaps-ingest-2026                        │   │
│   │  Method:   POST                                                       │   │
│   │                                                                       │   │
│   │  Payload:                                                             │   │
│   │  {                                                                    │   │
│   │    "device_id": "dashcam-4A928016A02C1046",                          │   │
│   │    "detections": [                                                    │   │
│   │      {                                                                │   │
│   │        "ts": 1746377552043,                                          │   │
│   │        "lat": 33.841234,                                             │   │
│   │        "lon": -118.391234,                                           │   │
│   │        "class_label": "road_sign",                                   │   │
│   │        "overall_confidence": 0.847                                   │   │
│   │      }                                                                │   │
│   │    ]                                                                  │   │
│   │  }                                                                    │   │
│   │                                                                       │   │
│   │  Image Upload (separate):                                             │   │
│   │  POST /api/images                                                     │   │
│   │  Content-Type: multipart/form-data                                   │   │
│   │  Fields: detection_id, device_id, image (file)                       │   │
│   └──────────────────────────────────────────────────────────────────────┘   │
│                                                                                │
└───────────────────────────────────────────────────────────────────────────────┘

adacam-forwarder Service Design

# Key Design Points:

1. READ FROM FILES DIRECTLY (not odc-api REST):
   - Path: /data/recording/landmarks/*.json
   - Avoids dependency on odc-api.service
   
2. STATE TRACKING:
   - /data/adacam/forwarder_state.json
   - Track last_landmark_id to avoid re-sending
   
3. RETRY QUEUE:
   - /data/adacam/forward_queue.db (SQLite)
   - Failed POSTs queued for retry
   
4. GPS FALLBACK:
   - If landmark missing GPS, query Redis GNSSFusion30Hz
   
5. BATCH POSTING:
   - Max 200 detections per POST
   - Respects rate limits (429  exponential backoff)

bee-tunnel.service Design

[Unit]
Description=SSH Tunnel to Lucy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# CRITICAL: Must add host route before tunnel
ExecStartPre=/sbin/ip route add 192.168.0.5/32 dev wlp1s0f1
ExecStart=/usr/bin/ssh -i /data/ssh/bee_tunnel_key \
    -R 2222:127.0.0.1:22 \
    -N \
    -o ServerAliveInterval=30 \
    -o ServerAliveCountMax=3 \
    -o StrictHostKeyChecking=no \
    -o ExitOnForwardFailure=yes \
    root@192.168.0.5
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Why 127.0.0.1:22?

  • sshd.socket listens on all interfaces (including 127.0.0.1)
  • Using 192.168.0.10:22 causes hairpin routing through the AP radio
  • Packets destined for own AP IP don't return correctly
  • Results in "Error reading SSH protocol banner"

6. ADAMaps Ingest

Expected Payload Format

POST /api/ingest
Content-Type: application/json
X-AdaMaps-Key: adamaps-ingest-2026

{
  "device_id": "dashcam-4A928016A02C1046",
  "detections": [
    {
      "ts": 1746377552043,
      "lat": 33.841234,
      "lon": -118.391234,
      "class_label": "road_sign",
      "overall_confidence": 0.847,
      "heading_deg": 127.4,
      "speed_mph": 35.2
    },
    {
      "ts": 1746377553123,
      "lat": 33.841456,
      "lon": -118.391567,
      "class_label": "lane_marking",
      "overall_confidence": 0.923
    }
  ]
}

Response:

{
  "ok": true,
  "accepted": 2,
  "detection_ids": [12345, 12346]
}

Image Upload Flow

Step 1: POST detections → receive detection_ids
Step 2: For each detection with image:
        POST /api/images
        multipart/form-data:
          - detection_id: 12345
          - device_id: dashcam-4A928016A02C1046
          - image: <binary JPEG>

Response:

{
  "ok": true,
  "image_id": "img_abc123",
  "url": "https://cdn.adamaps.org/observations/img_abc123.jpg"
}

Device Registration

POST /api/devices/register
Content-Type: application/json
X-AdaMaps-Key: adamaps-ingest-2026

{
  "device_id": "dashcam-4A928016A02C1046",
  "device_type": "hivemapper_bee",
  "firmware_version": "5.7.88",
  "owner_id": "user_cobb",
  "location_hint": "Redondo Beach, CA"
}

Response:

{
  "ok": true,
  "device_id": "dashcam-4A928016A02C1046",
  "api_key": "device-specific-key-here",
  "registered_at": "2026-03-22T18:00:00Z"
}

Complete Data Flow Diagram

┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                    COMPLETE DATA PIPELINE                                        │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                  │
│  ╔═══════════════════════════════════════════════════════════════════════════════════════════╗ │
│  ║                                  HIVEMAPPER BEE                                            ║ │
│  ╠═══════════════════════════════════════════════════════════════════════════════════════════╣ │
│  ║                                                                                            ║ │
│  ║  CAPTURE LAYER                                                                             ║ │
│  ║  ┌─────────────┐   ┌──────────────┐   ┌──────────────┐   ┌────────────────┐               ║ │
│  ║  │   Camera    │──▶│  depthai_    │──▶│  VPU Blob    │──▶│  Raw Frames    │               ║ │
│  ║  │  OV10640    │   │  gate        │   │  Inference   │   │  + Detections  │               ║ │
│  ║  │  2028x1024  │   │              │   │  YOLOv8-nano │   │                │               ║ │
│  ║  └─────────────┘   └──────────────┘   └──────────────┘   └───────┬────────┘               ║ │
│  ║                                                                   │                        ║ │
│  ║  ─────────────────────────────────────────────────────────────────┼─────────────────────── ║ │
│  ║                                                                   ▼                        ║ │
│  ║  PROCESSING LAYER                                                                          ║ │
│  ║  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐                                   ║ │
│  ║  │    GPS      │──▶│   Redis      │──▶│   map-ai     │                                   ║ │
│  ║  │  (u-blox)   │   │  Fusion      │   │   Python     │                                   ║ │
│  ║  └──────────────┘   └──────────────┘   │              │                                   ║ │
│  ║                                         │  Nodes:      │                                   ║ │
│  ║  ┌──────────────┐   ┌──────────────┐   │  -Locate     │                                   ║ │
│  ║  │    IMU      │──▶│   Redis      │──▶│  -Store      │                                   ║ │
│  ║  │  (SPI)      │   │  Handler     │   │  -Privacy    │                                   ║ │
│  ║  └──────────────┘   └──────────────┘   └──────┬───────┘                                   ║ │
│  ║                                                │                                           ║ │
│  ║  ─────────────────────────────────────────────┼────────────────────────────────────────── ║ │
│  ║                                                ▼                                           ║ │
│  ║  STORAGE LAYER                                                                             ║ │
│  ║  ┌───────────────────────────────────────────────────────────────────────────────────┐   ║ │
│  ║  │                           /data/recording/                                         │   ║ │
│  ║  │                                                                                    │   ║ │
│  ║  │  landmarks/*.json        ◀── Detection files (CLASS, CONF, LAT, LON, TS)          │   ║ │
│  ║  │  cached_observations/    ◀── Cropped detection images                             │   ║ │
│  ║  │  framekm/*.tar.gz        ◀── Video bundles with metadata                          │   ║ │
│  ║  │                                                                                    │   ║ │
│  ║  │  odc-api.db (SQLite)     ◀── gnss, imu, magnetometer, config, state               │   ║ │
│  ║  │                              (NO detections in SQLite!)                            │   ║ │
│  ║  └───────────────────────────────────────────────────────────────────────────────────┘   ║ │
│  ║                                                │                                           ║ │
│  ║                                                │                                           ║ │
│  ╠════════════════════════════════════════════════╪═══════════════════════════════════════════╣ │
│  ║  EGRESS LAYER                                  │                                           ║ │
│  ║                                                ▼                                           ║ │
│  ║           ┌─────────────────────────────────────────────────────────────┐                 ║ │
│  ║           │                                                             │                 ║ │
│  ║           │      ┌─────────────────┐      ┌─────────────────┐          │                 ║ │
│  ║           │      │ BLOCK:          │      │ KEEP:           │          │                 ║ │
│  ║           │      │ odc-api         │      │ adacam-forwarder│───────────────┐            ║ │
│  ║           │      │ mitmproxy       │      │                 │          │    │            ║ │
│  ║           │      │ beekeeper-plugin│      │ Reads files     │          │    │            ║ │
│  ║           │      │ mender-client   │      │ directly, no    │          │    │            ║ │
│  ║           │      │ hivemapper-     │      │ odc-api dep     │          │    │            ║ │
│  ║           │      │   data-logger   │      │                 │          │    │            ║ │
│  ║           │      └─────────────────┘      └─────────────────┘          │    │            ║ │
│  ║           │                                                             │    │            ║ │
│  ║           └─────────────────────────────────────────────────────────────┘    │            ║ │
│  ║                                                                               │            ║ │
│  ╚═══════════════════════════════════════════════════════════════════════════════╪════════════╝ │
│                                                                                   │              │
│  ┌───────────────────────────────────────────────────────────────────────────────┼────────────┐ │
│  │                                                                               │            │ │
│  │  bee-tunnel.service                                                           │            │ │
│  │  ┌──────────────────────────────────────────────────────────────┐            │            │ │
│  │  │  SSH -R 2222:127.0.0.1:22 root@192.168.0.5 (Lucy)            │            │            │ │
│  │  │       (WiFi wlp1s0f1 → zerocool network)                      │            │            │ │
│  │  └──────────────────────────────────────────────────────────────┘            │            │ │
│  │                                   │                                           │            │ │
│  └───────────────────────────────────│───────────────────────────────────────────│────────────┘ │
│                                      │                                           │              │
│                                      ▼                                           │              │
│  ╔═══════════════════════════════════════════════════════════════════════════════╪════════════╗ │
│  ║                                 LUCY (192.168.0.5)                            │            ║ │
│  ║  ┌────────────────────────────────────────────────────────────────────────────┼──────────┐║ │
│  ║  │  Tunnel endpoint: localhost:2222                                           │          │║ │
│  ║  │  → ssh -p 2222 root@localhost   # Access Bee shell                        │          │║ │
│  ║  │  → curl localhost:2222/status    # (if HTTP tunnel)                        │          │║ │
│  ║  └────────────────────────────────────────────────────────────────────────────┼──────────┘║ │
│  ╚═══════════════════════════════════════════════════════════════════════════════╪════════════╝ │
│                                                                                   │              │
│                                                                                   │              │
│                                                                                   │              │
│  ╔═══════════════════════════════════════════════════════════════════════════════╪════════════╗ │
│  ║                             ADAMAPS INGEST                                     │            ║ │
│  ║                                                                               │            ║ │
│  ║  ┌────────────────────────────────────────────────────────────────────────────┼──────────┐║ │
│  ║  │  POST /api/ingest                                                          │          │║ │
│  ║  │  Header: X-AdaMaps-Key: adamaps-ingest-2026                               │          │║ │
│  ║  │                                                                            │          │║ │
│  ║  │  {                                                                         ◀──────────┘║ │
│  ║  │    "device_id": "dashcam-4A928016A02C1046",                                           ║ │
│  ║  │    "detections": [                                                                    ║ │
│  ║  │      {"ts": ..., "lat": ..., "lon": ..., "class_label": ..., "confidence": ...}     ║ │
│  ║  │    ]                                                                                  ║ │
│  ║  │  }                                                                                    ║ │
│  ║  │                                                                                       ║ │
│  ║  │  POST /api/images  (multipart: detection_id, device_id, image)                       ║ │
│  ║  └───────────────────────────────────────────────────────────────────────────────────────┘║ │
│  ║                                                                                           ║ │
│  ╚═══════════════════════════════════════════════════════════════════════════════════════════╝ │
│                                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────────────────────┘

Quick Reference: Service States

Services to KEEP (Liberation)

Service Purpose Notes
depthai_gate Camera capture + VPU inference Core functionality
map-ai Detection processing Remove odc-api dependency
redis Sensor data store Required by map-ai
redis-handler Sensor fusion Required by datalogger
hostapd WiFi AP 192.168.0.10 access
sshd SSH access Remote management

Services to KILL (Liberation)

Service Purpose Why Kill
odc-api REST API Bloated, can read files directly
mitmproxy Proxy to Cloudflare Hivemapper data exfil
beekeeper-plugin Hivemapper control Phone home
hivemapper-data-logger Data uploader Exfiltration
mender-client OTA updates Blocks liberation
here-plugin HERE Maps Unnecessary
model-zoo Model updates Hivemapper models
collectd Metrics Unnecessary
cpu-mem-logger Logging Unnecessary
vnstat/vnstatd Network stats Unnecessary
rm_vpu_daemon VPU daemon Unknown purpose

New Services to INSTALL (ADAMaps)

Service Purpose Location
adacam-forwarder Detection forwarding /data/adacam/
bee-agent-api Remote management API /data/adacam/
bee-tunnel SSH reverse tunnel systemd

Appendix: File Locations Reference

PERSISTENT (/data/ survives OTA):
├── /data/adacam/                    # ADAMaps config/state
│   ├── config.json                  # Device config
│   ├── forwarder_state.json         # Forwarding state
│   ├── forward_queue.db             # Retry queue
│   └── agent-config.json            # Agent API config
├── /data/recording/                 # All recording data
│   ├── landmarks/                   # Detection JSON files ← KEY
│   ├── cached_observations/         # Detection images ← KEY
│   ├── framekm/                     # Video bundles
│   ├── odc-api.db                   # SQLite (sensors only)
│   └── *.log                        # Service logs
├── /data/ssh/                       # SSH keys
│   └── bee_tunnel_key               # Tunnel key
└── /data/odc-api.db                 # SQLite database

VOLATILE (/tmp/, cleared on reboot):
├── /tmp/recording/pics/             # Live frames
└── /tmp/gate_fw_*/                  # VPU firmware

READ-ONLY (/opt/, /usr/):
├── /opt/map-ai/                     # Detection Python code
├── /opt/odc-api/                    # Node.js API (TO KILL)
├── /opt/dashcam/bin/                # Binary tools
└── /usr/bin/depthai_gate            # Camera binary

Document generated for Sulkta-Coop/adacam liberation project Source: bee-recon data, odc-api analysis, firmware extraction