Files
andrew 7ad995d8d1
ci / smoke (push) Canceled after 0s
feat(manual-batch): require plate number at manual mode start
Legacy manual batch start locked until plate entered:
- POST /api/batch/start manual branch returns 400 missing_plate when
  plate empty (strip + uppercase, no format regex)
- operator + monitoring start modals gain required plate input,
  confirm button disabled until filled
- operator plate tile also shows for manual batches (was do_manual only)
- do_manual unchanged (plate from DOs)
2026-10-02 15:10:13 +07:00

152 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).