# RTSPCamDigitDetection Backend This service reads frames from one or more RTSP cameras, crops user-defined ROIs (Regions of Interest) containing 7‑segment digits, runs a TensorFlow Lite digit classifier, and publishes the assembled numeric value to MQTT (e.g., for Home Assistant) [code_file:9][code_file:11]. It also exposes a Flask web UI/API for live video previews, snapshots, and ROI configuration [code_file:9]. ## High-Level Architecture * **`app.py` (Main Service):** Runs the Flask web server and the main processing loop. It drains results from the inference worker, handles MQTT publishing, and manages the rate-limiting logic per camera [code_file:9]. * **`inference.py` (Worker):** A background thread that performs the heavy lifting. It accepts frames, crops the ROIs, runs the TFLite model, and validates results against confidence thresholds and numeric ranges [code_file:11]. * **`manager.py` & `camera.py`:** Handles the RTSP connections, frame buffering, and camera configuration management. ## Configuration Configuration variables are defined directly at the top of the scripts for simplicity. ### 1. Main Settings (`app.py`) Edit the top section of `app.py` to change these [code_file:9]: * **`DEBUG_LOG`** *(bool)*: * `True`: Enables verbose logging (heartbeats every 5s, per-task timing, detailed skip reasons). * `False`: Quiet mode. Only prints crucial info (MQTT publishes, connection errors). Warnings about skipped frames are rate-limited to once per minute to prevent log flooding. * **`DETECTION_INTERVAL`** *(int)*: * How often (in seconds) to attempt a detection for each camera (Default: `10`). * **`FRAME_STD_THRESHOLD`** *(float)*: * Standard Deviation threshold to filter out "bad" frames before inference. * Frames with contrast lower than this value are skipped. * *Recommendation:* Set to `0` or `1` if your valid digits are low-contrast. Set higher (e.g., `25`) only if you need to filter out specific gray/green encoding artifacts. ### 2. Inference Settings (`inference.py`) Edit the top section of `inference.py` to tune the AI [code_file:11]: * **`CONFIDENCE_THRESHOLD`** *(0.0 - 1.0)*: * Minimum confidence required for a digit to be accepted. * *Recommendation:* `0.85` is a good balance to prevent false positives like "1010" while accepting valid digits. * **`MIN_VALUE` / `MAX_VALUE`** *(int)*: * Sanity check range. Decoded numbers outside this range (e.g., `1010`) are discarded. ## How It Works (Logic & Logging) ### The "10s vs 60s" Behavior You might notice that successful detections are logged every **10 seconds**, but errors (like "Value out of range") appear only every **60 seconds**. * **Success:** The app attempts detection every `DETECTION_INTERVAL` (10s). Every success is logged immediately as INFO. * **Failure:** If the camera feed is bad or the value is out of range, the error technically occurs every 10s. However, when `DEBUG_LOG = False`, these repetitive warnings are suppressed and only printed **once per minute** to keep the CLI readable [code_file:9]. ### MQTT Behavior * **Topic:** `homeassistant/sensor/RTSPCamDigitDetection/state/` * **Payload:** `{"value": 42, "confidence": 0.98}` * **Trigger:** Published only on **successful** detection and validation. Errors are not published to this topic to avoid messing up sensor history. ## API Endpoints The app runs on port `5000` by default [code_file:9]. | Method | Endpoint | Description | | :--- | :--- | :--- | | `GET` | `/` | Web UI Entry point. | | `GET` | `/video/` | MJPEG stream for live preview. | | `GET` | `/snapshot/` | Capture a single JPEG snapshot. | | `GET` | `/cameras` | List configured cameras. | | `GET` | `/rois/` | Get current ROI definitions. | | `POST` | `/save_rois` | Save new ROI definitions to disk. | | `POST` | `/detect_digits` | Manual trigger: runs inference immediately and returns full debug details (JSON). |