varroa/docs/BEE-CAMERA.md

32 KiB
Raw Blame History

Bee Camera System — Full Technical Report

Generated: 2026-03-13


Executive Summary

The Hivemapper Bee dashcam uses an Intel Keem Bay SoC with an integrated Myriad X VPU for camera capture and ML inference. The camera pipeline flows from a Sony IMX378-equivalent sensor through MIPI CSI-2 to the VPU, where DepthAI firmware handles image processing and neural network inference. Frames are written to disk and exposed through multiple odc-api REST endpoints.

Key Findings:

  • Camera controlled via depthai_gate.service (Python/Flask on port 11492)
  • ML inference handled by map-ai.service using the VPU's Neural Compute Engine
  • Live frames stored in /tmp/recording/pics/
  • Landmark observation images stored in /data/recording/cached_observations/
  • Preview mode restarts the camera-bridge service with different configuration
  • No direct V4L2 access — all camera access goes through DepthAI pipeline

1. Hardware

1.1 System-on-Chip: Intel Keem Bay

Component Specification
SoC Intel Keem Bay (RVC2 / Robotics Vision Core 2)
CPU 4× ARM Cortex-A53 @ 1.5GHz
VPU Intel Movidius Myriad X (16 SHAVE cores)
NPU Integrated Neural Compute Engine (hardware inference)
RAM 4GB LPDDR4 (~3.5GB usable)
ISP Integrated Image Signal Processor on VPU
Process 10nm (Intel)

Memory Configuration:

MemTotal:        3,584,000 kB (~3.5GB)
SwapTotal:       2,097,148 kB (~2GB)
CmaTotal:        1,408,000 kB (~1.34GB reserved for VPU/camera DMA)

1.2 Camera Sensor

Specification Value
Sensor Sony IMX378 (or equivalent 12MP)
Resolution 4056 × 3040 native, downscaled to 2028 × 1024
Interface MIPI CSI-2
Frame Rate Variable, typically 30 FPS
ISP On-VPU processing via DepthAI

The Bee uses a Luxonis OAK-1 compatible camera module integrated with the Keem Bay SoC. The camera sensor connects directly to the SoC's MIPI CSI-2 interface, which is managed entirely by the DepthAI/Luxonis firmware running on the Myriad X VPU.

1.3 Bus Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     Intel Keem Bay SoC                          │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐  │
│  │ ARM Cortex   │  │ Myriad X VPU │  │ Neural Compute       │  │
│  │ A53 (4-core) │  │ (16 SHAVE)   │  │ Engine (NCE)         │  │
│  └──────┬───────┘  └──────┬───────┘  └──────────┬───────────┘  │
│         │                 │                      │               │
│         └────────┬────────┴──────────────────────┘               │
│                  │                                               │
│         ┌────────┴────────┐                                      │
│         │  Internal Bus   │                                      │
│         │  (AXI/NoC)      │                                      │
│         └────────┬────────┘                                      │
│                  │                                               │
│    ┌─────────────┼─────────────────────────────────────┐        │
│  ┌─┴──┐    ┌────┴────┐    ┌────────┐    ┌───────────┐ │        │
│  │PCIe│    │   USB   │    │  SDIO  │    │ MIPI CSI  │ │        │
│  └──┬─┘    └────┬────┘    └────┬───┘    └─────┬─────┘ │        │
└─────┼───────────┼──────────────┼──────────────┼────────┘        │
      │           │              │              │                  │
┌─────┴─────┐ ┌───┴───────┐  ┌──┴──┐      ┌────┴─────┐           │
│ Marvell   │ │ Telit     │  │eMMC │      │ Camera   │           │
│ 88W8997   │ │ LE910C4   │  │Flash│      │ Module   │           │
│ WiFi/BT   │ │ LTE Modem │  │     │      │ (IMX378) │           │
└───────────┘ └───────────┘  └─────┘      └──────────┘           │

2. Kernel / V4L2

2.1 Kernel Modules

The Bee runs a custom Yocto-based Linux with Intel-specific VPU drivers:

Module Purpose Status
kmb_cam (if present) Keem Bay camera driver Likely used internally
kmb_imx412 (if present) Sony IMX412 sensor driver May be loaded for sensor
videodev V4L2 subsystem Core video framework
v4l2_fwnode V4L2 firmware node parsing Device tree integration

Note: Standard V4L2 device access (/dev/video*) is not used for normal operation. The camera is accessed exclusively through the DepthAI XLink protocol running on the VPU. The VPU owns the camera hardware completely.

2.2 VPU Sysfs Interface

The VPU is controlled via sysfs:

/sys/class/vpu/

Firmware Loading:

  • luxonis_vpu.bin — DepthAI firmware (Luxonis/OAK)
  • vpu_nvr_b0.bin — Intel HDDL firmware (NOT used, conflicts)

The VPU firmware is written to a sysfs attribute (fwname) to trigger loading. The DepthAI firmware must load first, otherwise the Intel HDDL service (deviceservice) grabs the VPU and causes conflicts.

2.3 No Direct V4L2 Access

Important: You cannot access the camera via /dev/video* while depthai_gate is running. The DepthAI pipeline has exclusive ownership of the camera hardware. To get frames, you must:

  1. Use the existing depthai_gate/odc-api stack, OR
  2. Stop depthai_gate and implement your own DepthAI pipeline, OR
  3. Reverse-engineer XLink and write custom firmware

3. DepthAI Gate

3.1 Service Configuration

# depthai_gate.service (inferred from analysis)
[Unit]
Description=DepthAI Camera Gate
After=network.target

[Service]
Type=simple
User=root
ExecStart=/opt/depthai_gate/run.py
Restart=always

[Install]
WantedBy=multi-user.target

3.2 Technical Details

Property Value
Language Python 3 + Flask
Port 11492 (localhost)
Tasks ~158 threads observed
Memory ~200MB RSS
Location /opt/depthai_gate/ (estimated)

3.3 Responsibilities

  1. VPU Firmware Loading — Writes luxonis_vpu.bin to VPU sysfs
  2. XLink Connection — Establishes PCIe XLink to Myriad X VPU
  3. DepthAI Pipeline — Configures camera capture and ISP settings
  4. Frame Capture — Captures frames at configured resolution/framerate
  5. Frame Output — Writes frames to /tmp/recording/pics/

XLink is Luxonis's proprietary protocol for host-to-VPU communication:

  • Transport: PCIe (on Keem Bay) or USB (on desktop OAK devices)
  • Channels: Bidirectional data streams for frames, tensors, and control
  • Status Values:
    • 0 = Disconnected
    • 1 = Connecting / Error
    • 2 = Connected (good)

Status Check (from logs):

xlink_device_status=2   # Healthy
vpu_firmware=luxonis_vpu.bin

3.5 Pipeline Configuration

The DepthAI pipeline likely includes:

  • ColorCamera node — IMX378 capture at 4K, downscaled to 2028×1024
  • ImageManipNode — Resize, crop, color conversion
  • XLinkOut node — Send frames to host for storage
  • NeuralNetwork node (optional) — On-VPU inference

Pipeline configs may exist at:

  • /opt/depthai_gate/pipeline.json
  • /data/camera_config.json
  • Hardcoded in Python

3.6 VPU Conflict Bug

Root Cause (identified and fixed):

deviceservice.service (Intel HDDL / OpenVINO) was racing with depthai_gate.service:

  1. HDDL starts at boot, loads vpu_nvr_b0.bin
  2. depthai_gate starts, overwrites with luxonis_vpu.bin
  3. HDDL locked out, retries XLink every 2 seconds forever
  4. On depthai_gate restart, HDDL grabs VPU first → camera dead
  5. Watchdog (secure-wdtclient) crash loops → memory pressure → OOM

Fix:

systemctl disable --now deviceservice
systemctl mask deviceservice  # Survives OTA better

4. map-ai Pipeline

4.1 Service Configuration

# map-ai.service (inferred)
[Unit]
Description=Map AI Processing
After=depthai_gate.service

[Service]
Type=simple
User=root
ExecStart=/opt/map-ai/run.py
Restart=always

[Install]
WantedBy=multi-user.target

4.2 Technical Details

Property Value
Language Python 3
Model Format ONNX (via OpenVINO or DepthAI NCE)
Input Frames from depthai_gate
Output Detections to Redis, blurred frames to disk

4.3 Processing Pipeline

Frame from depthai → map-ai.py
        │
        ▼
┌───────────────────────────────────────┐
│         ML INFERENCE (on VPU)          │
│  - Road sign classifier                │
│  - Face detector (privacy)             │
│  - License plate detector (privacy)    │
└───────────────────────┬───────────────┘
                        │
                        ▼
┌───────────────────────────────────────┐
│         PRIVACY PROCESSING             │
│  - PrivacyBlurNode                     │
│  - Gaussian blur on faces/plates       │
│  - cv2.imwrite blurred frames          │
└───────────────────────┬───────────────┘
                        │
        ┌───────────────┴───────────────┐
        ▼                               ▼
Redis ZSET (detections)        Disk (blurred frames)

4.4 AI Models

Model Location Purpose
Road Signs /opt/object-detection/model.blob or /data/models/ Sign classification
Privacy /opt/odc-api/python/ or /data/models/ Face/plate detection
PVC /data/recording/models/pvc.onnx Unknown (227 bytes — likely index)

Privacy Model Hash: Stored in FrameKm metadata for verification.

4.5 Redis Integration

map-ai writes to Redis status keys:

GET MAP_AI_READY  →  "True"
GET EXTERNAL_MODEL_CLASSIFIER_READY  →  "True"

Detection results stored in SQLite, not Redis ZSETs.


5. Frame Storage

5.1 Storage Locations

Path Type Purpose Persistence
/tmp/recording/pics/ tmpfs Live camera frames Ephemeral
/tmp/recording/preview/ tmpfs Preview mode frames Ephemeral
/data/recording/cached_observations/ ext4 Landmark observation images Persistent
/data/recording/framekm/ ext4 FrameKm upload bundles Persistent
/tmp/rgb/ tmpfs Frame list files Ephemeral

5.2 Frame Format

Property Value
Format JPEG
Resolution 2028 × 1024
Quality ~85% (estimated ~150-200KB/frame)
Color RGB

5.3 Naming Convention

Live frames (/tmp/recording/pics/):

{system_time_ms}_{frame_id}_{sequence}.jpg
Example: 1709920000123_0001_0042.jpg

Cached observations (/data/recording/cached_observations/):

{timestamp}_{subsecond}_{frame_number}.jpg
Example: 1746377552_043000_2945056.jpg

5.4 Frame Purger

The folder_purger service manages disk space:

folder-purger /tmp/recording/pic 400000000 /mnt/data/gps 2000000000 ...

When /tmp/recording/pics/ exceeds 400MB, older frames are deleted.

5.5 Database Schema

Frames are tracked in SQLite (/data/recording/odc-api.db or data-logger.v2.0.0.db):

-- frames table
CREATE TABLE frames (
    system_time INTEGER PRIMARY KEY,
    image_name TEXT
);

Landmark observations reference frames:

-- observations table (simplified)
CREATE TABLE observations (
    id INTEGER PRIMARY KEY,
    landmark_id INTEGER,
    image_name TEXT,
    x1 REAL, y1 REAL, x2 REAL, y2 REAL,  -- bounding box
    ts INTEGER,
    ...
);

6. video-processor

6.1 Service Details

The video-processor service is not explicitly documented in the analyzed firmware, but based on naming patterns, it likely handles:

  1. FrameKm Bundling — Package frames + metadata for upload
  2. Video Encoding — H.264/H.265 encoding for preview/streaming
  3. Frame Sequencing — Order frames for FrameKm creation

6.2 FrameKm Format

Purpose: Bundle ~1km of driving data for upload to Hivemapper/HERE.

Path: /data/recording/framekm/

Contents:

framekm-2024-03-08-12-34-56-abc123.tar
├── manifest.json
├── frame_0001.jpg
├── frame_0002.jpg
├── ...
├── gnss_auth_buffer.bin
└── gnss_auth_signature.bin

Manifest Fields:

{
  "name": "framekm-2024-03-08-12-34-56-abc123",
  "numFrames": 150,
  "deviceId": "fvhL2I-iCT",
  "firmwareVersion": "0.0.1",
  "privacyModelHash": "sha256:abc123...",
  "gnssAuthBuffer": "base64...",
  "gnssAuthSignature": "base64...",
  "gnssAuthPublicKey": "base64...",
  "createdAt": 1709920000000
}

6.3 Relationship to Camera Frames

The video-processor does NOT produce the frames we care about for camera access. It only packages existing blurred frames for upload. For raw frame access, focus on depthai_gate and the preview system.


7. odc-api Camera Endpoints

7.1 Base URL

http://192.168.0.10:5000/api/1/

Binds to AP interface (wlp1s0f0) only — not accessible from home LAN directly.

7.2 Preview Endpoints

Endpoint Method Description
/preview/start GET Start preview mode (120s timeout)
/preview/stop GET Stop preview mode
/preview/status GET Check if preview is active
/preview/metadata GET Get latest frame metadata

Preview Implementation (util/preview.ts):

export const startPreview = async () => {
  // Create preview directory
  await execSync('mkdir /tmp/recording/preview');
  
  // Write preview config
  writeFileSync(IMAGER_CONFIG_PATH, JSON.stringify(getPreviewConfig()));
  
  // Restart camera-bridge with new config
  await execSync(CMD.STOP_CAMERA);  // systemctl stop camera-bridge
  await sleep(1000);
  await execSync(CMD.START_CAMERA); // systemctl start camera-bridge
};

Preview Timeout: 120 seconds (auto-stops to preserve 4K quality recording)

7.3 Landmark Image Endpoints

Endpoint Method Description
/landmarks/images/:id GET Get image paths for landmark
/landmarks/:id/chips GET Get chip endpoints for landmark
/landmarks/:id/chips/:chip_id GET Get cropped observation image (JPEG)
/landmarks/boundingBox/:id GET Get bounding box coordinates
/landmarks/upload PUT Upload landmark image to external URL

Image Retrieval Flow:

GET /landmarks/images/123
    ↓
Returns: ["/data/recording/cached_observations/1746377552_043000_2945056.jpg"]
    ↓
GET /landmarks/123/chips/456
    ↓
Returns: Cropped JPEG (bounding box region)

7.4 Camera Configuration

Config Path: /opt/camera-bridge/config.json

Commands (from bee.ts):

export const CMD = {
  RESTART_CAMERA: 'systemctl restart camera-bridge',
  START_CAMERA: 'systemctl start camera-bridge',
  STOP_CAMERA: 'systemctl stop camera-bridge',
  START_PREVIEW: 'systemctl start camera-preview',
  STOP_PREVIEW: 'systemctl stop camera-preview',
  // ...
};

7.5 Frame Retrieval

There is no direct /camera/frame endpoint in the current odc-api. To get a camera frame:

  1. Via Preview Mode:

    • Call /preview/start
    • Read frames from /tmp/recording/preview/
    • Call /preview/stop when done
  2. Via Landmark Images:

    • Call /landmarks/last/N to get recent detections
    • Call /landmarks/images/:id to get observation image paths
    • Call /landmarks/:id/chips/:chip_id to get cropped JPEG
  3. Direct File Access (SSH):

    • Read from /tmp/recording/pics/ for latest frames
    • Read from /data/recording/cached_observations/ for landmark images

8. Full Data Flow

8.1 Complete Pipeline

┌──────────────────────────────────────────────────────────────────────────────┐
│                              CAMERA CAPTURE                                   │
│  IMX378 Sensor → MIPI CSI-2 → VPU ISP → DepthAI Pipeline                     │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                          DEPTHAI_GATE (port 11492)                            │
│  - XLink communication with Myriad X VPU                                      │
│  - Frame capture from DepthAI pipeline                                        │
│  - Writes frames to /tmp/recording/pics/                                      │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    │
                    ┌───────────────┴───────────────┐
                    ▼                               ▼
┌───────────────────────────────┐   ┌──────────────────────────────────────────┐
│       RAW FRAME STORAGE       │   │              MAP-AI INFERENCE             │
│  /tmp/recording/pics/         │   │  - Road sign detection (VPU NCE)         │
│  - Temporary frames           │   │  - Privacy blur (faces/plates)           │
│  - Purged when >400MB         │   │  - Outputs to Redis + SQLite             │
└───────────────────────────────┘   └─────────────────┬────────────────────────┘
                                                      │
                    ┌─────────────────────────────────┤
                    ▼                                 ▼
┌───────────────────────────────────┐   ┌──────────────────────────────────────┐
│      CACHED OBSERVATIONS          │   │           LANDMARK DATABASE           │
│  /data/recording/                 │   │  /data/recording/odc-api.db           │
│    cached_observations/           │   │  - landmarks table                    │
│  - Persistent blurred frames      │   │  - observations table                 │
│  - Referenced by landmark ID      │   │  - frames table                       │
└───────────────────┬───────────────┘   └─────────────────┬────────────────────┘
                    │                                     │
                    └──────────────┬──────────────────────┘
                                   ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                          ODC-API (port 5000)                                  │
│  - /preview/* — Start/stop preview mode                                       │
│  - /landmarks/last/N — Get recent detections                                  │
│  - /landmarks/images/:id — Get observation image paths                        │
│  - /landmarks/:id/chips/:chip_id — Get cropped JPEG                           │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                          FRAMEKM BUNDLING                                     │
│  hivemapper-data-logger                                                       │
│  - Collect ~1km of frames + metadata                                          │
│  - Bundle with GNSS auth signatures                                           │
│  - Store at /data/recording/framekm/                                          │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                            UPLOAD PATH                                        │
│  odc-api → mitmdump (port 8888) → Cloudflare Workers → HERE OLP              │
└──────────────────────────────────────────────────────────────────────────────┘

8.2 Single Detection Event Trace

1. Camera captures frame
   └── IMX378 → MIPI → VPU ISP → depthai_gate

2. Frame written to disk
   └── /tmp/recording/pics/1709920000123_0001_0042.jpg

3. map-ai reads frame
   └── Runs road sign classifier on VPU NCE

4. Detection found (speed limit 35)
   └── Privacy blur applied to any faces/plates

5. Observation stored
   └── SQLite: observations table (landmark_id, bbox, ts, image_name)
   └── File: /data/recording/cached_observations/...

6. Landmark created/updated
   └── SQLite: landmarks table (class_label, lat, lon, confidence)

7. odc-api exposes data
   └── GET /landmarks/last/5 returns detection
   └── GET /landmarks/images/{id} returns image path
   └── GET /landmarks/{id}/chips/{chip_id} returns cropped JPEG

9. Replacement Considerations

9.1 Accessing Frames Without odc-api

Option 1: Direct File Read

# SSH to Bee
ssh -p 2222 root@localhost  # via Lucy tunnel

# Read latest frames
ls -lt /tmp/recording/pics/ | head -10
cp /tmp/recording/pics/latest_frame.jpg /tmp/

# Stream frames (naive)
while true; do
  cp $(ls -t /tmp/recording/pics/*.jpg | head -1) /tmp/current.jpg
  sleep 0.033  # ~30 FPS
done

Pros: Simple, no service changes
Cons: Race conditions, no metadata

Option 2: Redis Pub/Sub Subscribe to frame events if depthai_gate publishes them:

import redis
r = redis.Redis()
p = r.pubsub()
p.subscribe('frame_ready')
for message in p.listen():
    print(message)  # Contains frame path or metadata

Pros: Event-driven, no polling
Cons: May not exist in current firmware

9.2 Accessing Frames Without depthai_gate

Not recommended — requires implementing your own DepthAI pipeline.

If you must:

  1. Stop depthai_gate: systemctl stop depthai_gate
  2. Use Luxonis depthai Python SDK
  3. Create minimal pipeline:
import depthai as dai

pipeline = dai.Pipeline()
cam = pipeline.create(dai.node.ColorCamera)
cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_4_K)
cam.setIspScale(1, 2)  # Downscale to 2028x1024

xout = pipeline.create(dai.node.XLinkOut)
xout.setStreamName("video")
cam.video.link(xout.input)

with dai.Device(pipeline) as device:
    q = device.getOutputQueue("video")
    while True:
        frame = q.get()
        cv2.imwrite("/tmp/frame.jpg", frame.getCvFrame())

Pros: Full control over camera
Cons: Breaks all Hivemapper services, loses ML pipeline

9.3 Minimal Path to JPEG Frame

Fastest (with existing stack):

# Via SSH
ssh -p 2222 root@localhost 'ls -t /tmp/recording/pics/*.jpg | head -1 | xargs cat' > frame.jpg

Via API (requires preview mode):

curl http://192.168.0.10:5000/api/1/preview/start
sleep 2
ssh -p 2222 root@localhost 'ls -t /tmp/recording/preview/*.jpg | head -1 | xargs cat' > frame.jpg
curl http://192.168.0.10:5000/api/1/preview/stop

9.4 Building a Custom Camera Interface

Requirements:

  1. Maintain depthai_gate (or reimplement VPU control)
  2. Expose a REST endpoint for single-frame capture
  3. Optionally implement MJPEG streaming

Proposed odc-api Addition:

// routes/camera.ts
router.get('/frame', async (req, res) => {
  const frames = readdirSync('/tmp/recording/pics')
    .filter(f => f.endsWith('.jpg'))
    .sort()
    .reverse();
  
  if (frames.length === 0) {
    return res.status(404).send('No frames available');
  }
  
  const framePath = join('/tmp/recording/pics', frames[0]);
  res.sendFile(framePath);
});

router.get('/stream', async (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'multipart/x-mixed-replace; boundary=frame',
    'Cache-Control': 'no-cache',
  });
  
  const interval = setInterval(() => {
    const frames = readdirSync('/tmp/recording/pics')
      .filter(f => f.endsWith('.jpg'))
      .sort()
      .reverse();
    
    if (frames.length > 0) {
      const framePath = join('/tmp/recording/pics', frames[0]);
      const frameData = readFileSync(framePath);
      
      res.write('--frame\r\n');
      res.write('Content-Type: image/jpeg\r\n');
      res.write(`Content-Length: ${frameData.length}\r\n\r\n`);
      res.write(frameData);
      res.write('\r\n');
    }
  }, 33);  // ~30 FPS
  
  req.on('close', () => clearInterval(interval));
});

9.5 Architecture for Replacement System

┌──────────────────────────────────────────────────────────────────┐
│                    VARROA CAMERA SERVICE                          │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌─────────────────┐    ┌─────────────────┐    ┌──────────────┐ │
│  │  depthai_gate   │ →  │  varroa-camera  │ →  │   HTTP API   │ │
│  │  (unchanged)    │    │  (new service)  │    │   (port 80)  │ │
│  └─────────────────┘    └─────────────────┘    └──────────────┘ │
│         ↓                       ↓                     ↓          │
│  /tmp/recording/pics/   Monitor & serve       GET /frame         │
│                         frames via inotify    GET /stream        │
│                                               GET /landmarks     │
└──────────────────────────────────────────────────────────────────┘

10. Open Questions

Question Priority How to Investigate
Exact depthai_gate pipeline config High SSH in, find config files in /opt/
Does depthai_gate publish to Redis? High redis-cli MONITOR while recording
Camera-bridge vs depthai_gate relationship High Check systemd deps, trace with strace
Preview config format Medium Read getPreviewConfig() implementation
ML model exact location on Bee Medium find /opt /data -name "*.blob" -o -name "*.onnx"
Frame timestamp accuracy Medium Compare frame timestamps to GNSS time

Appendix A: Key File Paths

Path Purpose
/tmp/recording/pics/ Live camera frames
/tmp/recording/preview/ Preview mode frames
/data/recording/cached_observations/ Landmark observation images
/data/recording/framekm/ FrameKm upload bundles
/data/recording/odc-api.db SQLite database
/opt/camera-bridge/config.json Camera configuration
/opt/depthai_gate/ DepthAI service (estimated)
/opt/odc-api/ Node.js API service
/sys/class/vpu/ VPU sysfs interface

Appendix B: Service Dependencies

multi-user.target
    │
    ├── redis.service              [t+2s]
    │
    ├── depthai_gate.service       [t+8s]   # MUST start before map-ai
    │       │
    │       └── Loads luxonis_vpu.bin
    │
    ├── map-ai.service             [t+12s]  # Depends on depthai_gate
    │       │
    │       └── Privacy blur, ML inference
    │
    ├── hivemapper-data-logger.service [t+15s]
    │
    └── odc-api.service            [t+18s]  # REST API

Appendix C: Port Reference

Port Service Protocol Binding
22 sshd TCP AP only (via socket)
5000 odc-api HTTP AP interface
6379 Redis TCP localhost
8888 mitmdump HTTP localhost
11492 depthai_gate HTTP/Flask localhost

End of Report