# Configuration Canonical source: **`config.yaml`** (repo root) — stream, models, counting knobs, batch, output paths, camera. Loaded once at startup via `src/config_loader.py` (stdlib dataclasses + pyyaml, no heavy deps). Secrets & deployment-only values stay in `.env`. Zone polygons stay in `zones.json`. Tracker hyperparams stay in `cfg/tracker.yaml`. ``` config.yaml canonical: stream/models/counting/batch/output/camera .env secrets + deployment: RTSP_URL, dashboard host/ports/secret/site zones.json geometry: palet/truck/counting polygons + left/right limits cfg/tracker.yaml tracker hyperparams (FastTrack/ByteTrack tuning) ``` Model modes are **data** (`config.yaml` → `models.modes`): each preset declares only `engines` (path key + contributed classes) and `class_filters`. Per-class `conf`/`iou`/`min_bbox_area` live in `models.detection_params` and apply to ALL modes. `detection_params.*.conf` is the **authoritative detection floor** — `predict.py` no longer hardcodes a second gate (old 0.50 sack / 0.45 truck overrides are gone). `counting.cross_class_iou` (default 0.4) drops sack detections that overlap a box detection (v4 has no box class); `<= 0` disables. Adding mode E/F/... is a YAML-only change — `predict.py` derives tracker roles structurally, and the dashboard `/api/model-modes` endpoint lists them automatically. Mode switch: dashboard `POST /api/batch/mode {"model_mode": "X"}` validates against `config.yaml` and persists atomically (tmp+replace, comments preserved) to `models.active_mode`. **Manual `karung-counter` restart still required** (models load once at startup). `batch_mode.json` keeps only the batch flow `mode` (`auto` | `do_manual` | `manual`); its legacy `model_mode` key is ignored (warned). `MODEL_MODE` env var still overrides for one run but is deprecated (warned). **Batch flow modes** (`batch.default_mode` in YAML; runtime `batch_mode.json`): | Mode | Who opens/closes | DO gate | |---|---|---| | `auto` (default) | AI truck FSM | n/a | | `do_manual` | Operator start/stop + staged DO photos | yes | | `manual` | Operator start/stop (legacy) — plate required at start | no | `POST /api/batch/mode` with `mode` and/or `model_mode` is **office port only** (403 on operator `:5000`); mode switch while a batch is active → **409**. `GET /api/batch/mode` works on both ports (`mode_editable` / `model_mode_editable`). **Auto-mode timers** (`batch:` in `config.yaml`, comments inline): | Key | Default | Controls | |---|---|---| | `timeout_seconds` | `20` | sack-idle: N s with no crossing **and** no sack visible in the truck area → batch pauses (`WAITING_FOR_ACTIVITY`) | | `truck_gone_tolerance_seconds` | `30` | truck-gone: in `WAITING_FOR_ACTIVITY`, N s with no crossing + no visible sack + no valid truck signal → batch finalized | `--batch-timeout` (dev CLI) overrides both for one run. Truck presence (`truck_in_area`) accepts a bbox with ≥50 % area overlap of `detection_polygon` (100 % containment made the signal flicker for big docked trucks); transitions are logged as `[TRUCK] truck_in_area ...`. **DO block** (`do:` in `config.yaml`): `enabled`, `require_do`, `require_plate` (default seed), `retention_days: 7`, `photo_dir: do_photos`, `max_photos_per_batch`, `zone_warn_seconds`, `ocr.engine` (YAML seed only). **Runtime DO settings** (`$OUTPUT_DIR/do_settings.json`): `require_plate` / `require_do` / `ocr_engine` (`rapid`|`tesseract`|`paddle`|`none`, default `rapid`) — **office-only write** (403 on operator). Sync via `GET/POST /api/do/settings`. Engine flip applies to the next upload without restart. Template: `.env.example`. Production values live in `.env` (git-ignored). Missing `config.yaml` falls back to `.env` + built-in defaults with a warning (see `src/config_loader.py`); explicit legacy path env vars below still override when set. ## 1. `.env` (secrets & deployment — `predict.py` / `counter_dashboard.py`) | Key | Default | Meaning | |---|---|---| | `OUTPUT_DIR` | `/opt/jetson-counter` | Legacy override of `output.dir` when set | | `DB_PATH` | `$OUTPUT_DIR/jetson_counter.db` | Legacy override of the SQLite path when set | | `STATE_FILE` | `$OUTPUT_DIR/current_batch.json` | Legacy override of the live batch state path when set | | `BATCH_MODE_FILE` | `$OUTPUT_DIR/batch_mode.json` | Legacy override (file keeps only batch flow mode: auto/do_manual/manual) | | `DO_SETTINGS_PATH` | `$OUTPUT_DIR/do_settings.json` | Runtime DO settings (require_plate/do, ocr_engine) | | `DO_PHOTO_ROOT` | `$OUTPUT_DIR/do_photos` | DO photo tree root | | `LIVE_STREAM_FRAME_PATH` | `/dev/shm/jetson-counter/live_frame.jpg` | Legacy override of the annotated frame path when set | | `CAMERA_NAME` | `CC1` | Camera tag stored per batch | | `OBJECT_LABEL` | `karung-pakan` | Object tag stored per batch | | `DAILY_CUTOFF_TIME` | `06:00` | Counting-day boundary (`get_counting_date`) | | `SECRET_KEY` | — | Flask session key (**change in production**) | | `DASHBOARD_HOST` / `DASHBOARD_PORT` | `0.0.0.0` / `5000` | Dashboard bind | | `OFFICE_PORT` | `5721` | Second dashboard port | | `FLASK_DEBUG` | `false` | Flask debug | | `RTSP_URL` | — | Camera stream URL (env-only, never in YAML) | | `MOTIONEYE_URL` | `""` | motionEye base URL for batch clip download (empty disables the endpoint) | | `MOTIONEYE_CAMERA_ID` | `2` | motionEye camera id used for batch clip download | | `MOTIONEYE_CLIP_PAD` | `3` | Seconds padded before/after the batch window when trimming the clip (float) | | `MOTIONEYE_OSD_ALIGN` | `1` | `1` = OCR-correct burned-in OSD clock drift at cut points, `0` = filename-based offsets only | | `MODEL_PATH` | — (deprecated) | Single-file v4 override, folded into `models.paths` | | `MODEL_MODE` | — (deprecated) | One-run override of `models.active_mode` (warned) | | `BATCH_MERGE_THRESHOLD_SECONDS` | `300` | Merge window for adjacent batches | On Windows dev machines these resolve to `d:/Belajar/menghitung karung/...`. ## 2. `src/config.py` keys (deprecated v3 `src/main.py --env`) ⚠️ **Deprecated** — the v3 loop is retired; production uses `config.yaml` via `src/config_loader.py`. Documented here only because the old keys still exist in code. Do not add new keys here. ⚠️ **Different names** from the table above — the v3 loader uses its own keys: | Key | Default | |---|---| | `LOCAL_RTSP` / `JETSON_RTSP` | `""` | | `MODEL_SACK_PATH` / `MODEL_TRUCK_PATH` | `./models/best.engine`, `./models/truck-detector.engine` | | `COUNTING_LINE_Y` / `_X_START` / `_X_END` | `0.60` / `0.38` / `0.72` (fractions; initial line before ROI sync) | | `SACK_CONF_THRESHOLD` / `TRUCK_CONF_THRESHOLD` | `0.40` / `0.50` | | `BATCH_TIMEOUT_SECONDS` | `30` | | `CSV_OUTPUT_DIR` | `./output` | | `DATA_SEED` | `42` | CLI: `python -m src.main --source video.mp4 --env .env`. ## 3. `zones.json` (calibrated geometry, 1920×1080 reference) - `palet` / `truck` / `counting` — zone polygons; scaled to actual resolution at startup. - `left_limit` / `right_limit` (`0.27578` / `0.72578`) — counting X band. - `external_stream_url` — MediaMTX restream endpoint. - Legacy knob keys (`duplicate_circle_radius`, `min_valid_area`, `jarak_toleransi_duplikat`, `max_reid_transit_distance`, `circle_stay_timeout_sec`, `inference_stride`, `confirm_delay_sec`, `exit_confirm_delay_sec`) are **ignored with a warning** — they moved to `config.yaml counting.*` / `stream.inference_stride`. Keep only geometry here. Recalibrate with `archive/get_coordinates.py` / `archive/get_calib_frame.py` (`calib_frame.jpg`). ## 4. `cfg/tracker.yaml` (FastTrack/ByteTrack tuning) `track_buffer=60` (~2.4 s lost-track hold for worker occlusion), `new_track_thresh=0.30` (anti-duplicate IDs), `track_high/low_thresh=0.20/0.05`, `match_thresh=0.85`, `active_occ_to_lost_thresh=15`, `occ_reappear_window=60`, `enlarge_bbox_occ=1.15`, `occ_cover_thresh=0.6`, Kalman offsets + `init_iou_suppress=0.65`. Falls back to stock `bytetrack.yaml` if the file is missing (`src/tracking.py:39`). ## 5. `archive/rpo_iki/configs/` (retired alternate engine, not imported) `area_truk*.json` (per-camera truck areas), `cameras.json` (cam1/cam2 RTSP), `counting_params.json` (+ `counting_params_last_truck.json`, hot-reloaded by `count.py`), `model_registry.json` (pinned model + metrics), `telegram.json` (notification settings).