Configuration
How helios.toml resolves, every knob it exposes, camera-index discovery, and virtual-camera notes.
Per-device tuning lives in helios.toml. Moving Helios between machines is a profile change, never a code change.
Resolution order
Effective config is resolved lowest to highest:
- Built-in defaults.
- The
[default]table inhelios.toml. - The
[profiles.<hostname>]table matching this machine's hostname. - CLI flags.
Get the hostname key for a machine:
python -c "import socket; print(socket.gethostname())"Then add a profile keyed by it, overriding only what you need:
[profiles.your-hostname]
model = "yoloe-11s-seg.pt" # -11s (fast) ... -11l (accurate)
imgsz = 640 # 480/512/640/896 — lower = faster
conf = 0.25 # detection/draw threshold
target_fps = 30A typo'd hostname fails silently — by design
A missing or misspelled profile key falls back to [default], so the machine simply runs untuned
rather than erroring. If tuning appears to have no effect, confirm the profile key matches the
real hostname exactly.
How the loader handles bad input
- Unknown keys are dropped, in both
[default]and the host profile. - A value that cannot be coerced to its declared type falls back to that field's built-in default, so one bad value cannot take down the whole load.
- A missing or unreadable config file falls back to the built-in defaults — no profile, no overrides.
- Malformed TOML raises. This is a real operator error and is not swallowed into a silent default.
CLI flags
--device, --camera, --model, --imgsz, --target-fps, and --conf override everything else. uvicorn is not flag-aware, so use a module entry point when experimenting — for example python -m app.vision --selftest --camera 700 honors helios.toml and the flags together.
Every knob
| Key | Default | Meaning |
|---|---|---|
device | "cuda:0" | CUDA device to load the detector onto. Validated at startup; there is no CPU path. |
camera_index | 0 | OpenCV camera index to capture from. |
capture_backend | "auto" | "auto" tries DirectShow then Media Foundation; or force "dshow" / "msmf". |
model | "yoloe-11s-seg.pt" | YOLOE weights. Bigger variants are more accurate and slower. |
tracker | "bytetrack.yaml" | Ultralytics tracker config used for counting. botsort.yaml for occlusion. |
imgsz | 640 | Inference size. Larger improves small-object recall at an FPS cost. |
target_fps | 30 | Caps the capture loop, which saves GPU and stabilizes pacing. |
conf | 0.25 | Confidence threshold for detecting and drawing. Higher = fewer, steadier boxes. |
max_concepts | 8 | Upper bound on how many concepts Claude may return for one prompt. |
llm_model | "claude-sonnet-4-6" | Claude model used for concept mapping and policy parsing. |
starter_concepts | ["person", "laptop", "cup", "bottle", "chair"] | Vocabulary bound before the first chat message. |
smoothing_window | 8 | Frames in the rolling majority vote for PPE and zone state. |
smoothing_min_ratio | 0.6 | Fraction of the window that must agree to hold a state. |
smoothing_evict_after | 15 | Frames a vanished track survives before its history is dropped. |
tiling_enabled | false | Startup default for the tiling toggle only; the live UI toggle wins afterward. |
tile_size | 640 | Tile edge length for the tiling path. Config-only. |
tile_overlap | 128 | Tile overlap in pixels for the tiling path. Config-only. |
See Tuning for how to choose values for the smoothing, FPS, and tiling knobs.
Camera selection
OpenCV identifies cameras only by index and cannot name them, so finding the right one is trial and error. List what is available:
python -m app.capture --list # prints index -> device nameSet the winning index (and, on Windows, a backend) in the machine's profile:
[profiles.your-hostname]
camera_index = 1
capture_backend = "auto" # "auto" tries DSHOW then MSMF; or force "dshow"/"msmf"If the listing command reports that cv2_enumerate_cameras is not installed, install it — it is the optional package that provides index-to-name discovery.
Sources, by latency
Best first:
- Built-in or USB webcam — plug and play.
- A phone as a virtual webcam (via an app such as Camo or EpocCam) — registers a virtual camera device. Use a wired USB connection for lowest latency. The phone app must be running and showing a live preview first, or the virtual device is missing or yields black frames.
- A mirrorless camera through an HDMI-to-USB UVC capture card (1080p) or a vendor webcam utility (around 720p) — appears as an ordinary camera index.
Virtual-camera notes
Virtual webcams often return a successful read but all-black frames on the wrong backend. capture_backend = "auto" opens with DirectShow first (most compatible), falls back to Media Foundation, and rejects an all-black test frame automatically — so this is usually handled for you.
If the feed is black with no error card, the phone or capture app most likely is not streaming yet: open its preview, or reconnect the USB cable.
Helios also tolerates a short burst of dropped frames from a real webcam; only a sustained run of failed reads escalates to the CAMERA_UNAVAILABLE error card.