# Cold Display Guard Project Documentation ## Goal `cold-display-guard` monitors refrigerated display food batches by camera region. It tracks how long each configured food region remains occupied, raises a configurable time alarm, and escalates alarmed food to a warning if it is removed without a matching trash-bin deposit. The `v1.1 优化改造` batch upgrades the product from a fixed 8-zone layout to a configurable 1-10 zone workflow with numeric region labels and editable trash ROI calibration. All v1.1 items are part of one batch; backend, API, frontend, and documentation are implementation workstreams inside that same batch. ## Architecture - Backend package: `src/cold_display_guard/` - `models.py`: settings, observations, and batch dataclasses. - `engine.py`: deterministic batch state machine. - `config.py`: TOML config load/save, calibration merge, and project path resolution. - `manage_api.py`: standard-library HTTP management API. - `main.py`: RTSP runtime loop connecting frame capture, vision, state engine, and JSONL sinks. - `vision.py`: heuristic ROI occupancy and trash-motion detection. - Frontend package: `web/` - Vite + vanilla JavaScript management console. - Default web port `23000`. - API proxy target `http://127.0.0.1:19080`. - Runtime home view falls back to clearly marked demo data when no real events exist, so the operational layout still shows summary cards, dwell timers, and event rows. - Runtime data: - Events JSONL default path `logs/events.jsonl`. - Diagnostics JSONL default path `logs/runtime_diagnostics.jsonl`. - Deployment: - Root Python Docker image for API/runtime. - `web/Dockerfile` for static web console. - `deploy/docker-compose.yml` wires API, runtime, and web services. ## Configuration - Main config path: `config/example.toml`. - Camera identity: `camera_id`. - Timezone default: `Asia/Shanghai`. - RTSP input: `[stream] rtsp_url`. - Thresholds: - `max_dwell_seconds`: v1.1 time-alarm threshold. Default can remain 10800 seconds; users can set values such as 1200 seconds for 20 minutes. - `trash_confirmation_seconds`: window after an alarmed batch is removed where a trash deposit must be observed before warning escalation. - Food zones: - v1.1 food zone IDs are numeric strings from `"1"` through `"10"`. - The configured zone count must be between 1 and 10. - If both `zone_count` and numeric `zone_ids` are present, they must agree. - Each `[[zones]]` polygon must have at least 3 normalized points. - Trash ROI: - Stored under `[trash] roi`. - Does not use a food zone number. ## Event Model - `batch_started`: a food region changes from empty to occupied. - `time_alarm`: an active batch reaches `max_dwell_seconds` while still in the display region. - `batch_count_changed`: count decreases while the region remains occupied. - `mixed_batch_violation`: count increases before the region clears. - `batch_consumed`: a non-alarmed batch clears before the threshold. - `batch_pending_disposal`: an alarmed batch clears and waits for trash confirmation. - `batch_discarded`: a pending alarmed batch is matched to a trash deposit. - `warning_escalated`: a pending alarmed batch is not matched to a trash deposit before the confirmation deadline. Events should include `zone_id`, `zone_index`, `zone_label`, `started_at`, `dwell_seconds`, and relevant alarm/removal/deadline timestamps when available. ## Runbook - Python tests: - `PYTHONPATH=src python3 -m unittest discover -s tests -v` - Management API: - `scripts/run_manage_api.sh` - Health: `curl http://127.0.0.1:19080/api/manage/health` - Web console: - `scripts/run_web.sh` - Build: `cd web && pnpm build` - Frontend logic tests: `node --test web/test/zone-state.test.js` - Docker web URL: `http://127.0.0.1:23000` - Runtime monitor: - `scripts/run_runtime.sh` - One-frame smoke test when camera and `ffmpeg` are available: - `PYTHONPATH=src python3 -m cold_display_guard.main --config config/example.toml --once` ## Known Risks - The current vision detector is heuristic and reports binary occupancy, not item counts. - If food is already present during baseline collection, those regions may be treated as empty baseline until visual changes occur. - Changing calibration while the runtime process has active batches can create operational ambiguity; v1.1 should document or enforce a pause/restart expectation. - Historical events must keep the zone index at the time of emission so later region reordering does not reinterpret old logs.