Files
zenai-ktc-python/DEPLOY.md
T
2026-07-24 11:42:18 +07:00

281 lines
7.9 KiB
Markdown

# ZenAI KTC Counter — Edge Deployment Guide
Production deployment for **RK3588** (or compatible RKNN NPU) edge devices running a
**zone-based sack feeder counter** (left / right feeders):
| Component | Script | systemd unit |
|-----------|--------|--------------|
| RTSP counter (RKNN + ByteTrack + zones) | `counter_live_rknn.py` | `zenai-ktc-counter.service` |
| Web dashboard (Flask) | `counter_dashboard.py` | `zenai-ktc-dashboard.service` |
Both processes share a single `.env` file and read/write the same SQLite database and state JSON.
**Counting model:** two rectangular zones (left + right). A sack is counted once when its
centroid **enters** a zone. Left zone → left feeder; right zone → right feeder.
---
## 1. Prerequisites
### Hardware & OS
- RK3588 board (or Jetson/RK device with RKNN Lite runtime)
- Linux with systemd
- Network access to the RTSP camera stream
### System packages
```bash
sudo apt update
sudo apt install -y python3 python3-venv python3-pip ffmpeg libgl1
```
`ffmpeg` is required for low-latency RTSP capture via OpenCV. `libgl1` is often needed for `opencv-python` on headless systems.
### RKNN model
Export or copy your `.rknn` model to the device, e.g.:
```text
/opt/models/your_model.rknn
```
Set `MODEL_PATH` in `.env` to match. The model class count must match `NUM_CLASSES`, and `OBJECT_CLASS_ID` must point at the class you count.
---
## 2. Directory layout
Default paths used by the service files and `env.example`:
```text
/opt/zenai-ktc-python/ # application code (this repo)
├── counter_live_rknn.py
├── counter_dashboard.py
├── counter_store.py
├── templates/
├── venv/ # Python virtual environment (created during install)
├── .env # runtime config (not in git)
├── env.example # template — copy to .env
└── DEPLOY.md
/opt/zenai-ktc-counter/ # persistent runtime data (created automatically)
├── counter.db # SQLite daily records
├── current_counter.json # live counting-day state
├── snapshots/ # zone-entry/detect JPEGs (if enabled)
└── crossings.csv # optional per-event CSV
/opt/models/ # RKNN models (deploy separately)
/dev/shm/zenai-ktc-counter/ # live JPEG frame for dashboard video (tmpfs)
```
---
## 3. Install application
### 3.1 Copy code to the device
```bash
sudo mkdir -p /opt/zenai-ktc-python
sudo rsync -av --exclude venv --exclude .env --exclude __pycache__ \
./ /opt/zenai-ktc-python/
# Or: sudo git clone <repo-url> /opt/zenai-ktc-python
```
### 3.2 Create virtual environment and install dependencies
```bash
cd /opt/zenai-ktc-python
sudo python3 -m venv venv
sudo ./venv/bin/pip install --upgrade pip
sudo ./venv/bin/pip install -r requirements.txt
```
> `rknn-toolkit-lite2` is platform-specific. Install on the target ARM device, not on a Windows dev machine.
### 3.3 Create runtime config
```bash
cd /opt/zenai-ktc-python
sudo cp env.example .env
sudo nano .env
```
**Minimum values to edit before starting:**
| Variable | Description |
|----------|-------------|
| `SOURCE` | RTSP URL or local video file path |
| `MODEL_PATH` | Path to your `.rknn` model on device |
| `NUM_CLASSES` | Must match the exported model |
| `OBJECT_CLASS_ID` | Class index of the object being counted |
| `CLASS_OBJECT` / `OBJECT_LABEL` | Labels stored in DB (e.g. `karung`) |
| `ZONE_LEFT_*_FRAC` / `ZONE_RIGHT_*_FRAC` | Feeder zone rectangles (tune per camera) |
| `SECRET_KEY` | Random string for Flask sessions |
Ensure `STATE_FILE` and `DB_PATH` both live under `/opt/zenai-ktc-counter/` so data survives reboots (avoid `/tmp` in production).
### 3.4 Create data directories (optional — app creates most paths automatically)
```bash
sudo mkdir -p /opt/zenai-ktc-counter /opt/models /dev/shm/zenai-ktc-counter
```
---
## 4. Install systemd services
```bash
cd /opt/zenai-ktc-python
sudo cp zenai-ktc-counter.service zenai-ktc-dashboard.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable zenai-ktc-counter zenai-ktc-dashboard
sudo systemctl start zenai-ktc-counter
sudo systemctl start zenai-ktc-dashboard
```
The dashboard unit starts **after** the counter unit (`After=zenai-ktc-counter.service`).
### Verify
```bash
systemctl status zenai-ktc-counter
systemctl status zenai-ktc-dashboard
journalctl -u zenai-ktc-counter -f
```
Open the dashboard in a browser:
```text
http://<device-ip>:5000
```
(Port is set by `DASHBOARD_PORT` in `.env`, default `5000`.)
---
## 5. Tuning feeder zones
Zones are axis-aligned rectangles. Defaults cover the left and right sides of the frame:
```ini
ZONE_LEFT_X1_FRAC=0.00
ZONE_LEFT_Y1_FRAC=0.20
ZONE_LEFT_X2_FRAC=0.35
ZONE_LEFT_Y2_FRAC=0.85
ZONE_RIGHT_X1_FRAC=0.65
ZONE_RIGHT_Y1_FRAC=0.20
ZONE_RIGHT_X2_FRAC=1.00
ZONE_RIGHT_Y2_FRAC=0.85
```
For pixel-perfect placement, set absolute coordinates instead (they override fractions):
```ini
ZONE_LEFT_X1=40
ZONE_LEFT_Y1=120
ZONE_LEFT_X2=420
ZONE_LEFT_Y2=900
```
Enable `DEBUG_TRACKING=true` temporarily for verbose inherit / dup / cooldown logs.
Each successful count always prints a Frigate-style line to the journal:
```text
Total karung di kandang_bawah_feeder_kanan: 5
```
Set `FEEDER_LEFT_NAME` / `FEEDER_RIGHT_NAME` (and `OBJECT_LABEL`) in `.env` to match your site.
---
## 6. Operations
### Restart after config change
```bash
sudo systemctl restart zenai-ktc-counter
sudo systemctl restart zenai-ktc-dashboard
```
### View logs
```bash
journalctl -u zenai-ktc-counter -n 100 --no-pager
journalctl -u zenai-ktc-dashboard -n 100 --no-pager
```
### Stop services
```bash
sudo systemctl stop zenai-ktc-dashboard zenai-ktc-counter
```
The counter handles `SIGTERM` gracefully — it finishes the current frame, persists state to SQLite, then exits.
### Update application code
```bash
cd /opt/zenai-ktc-python
sudo systemctl stop zenai-ktc-dashboard zenai-ktc-counter
# rsync or git pull new code
sudo ./venv/bin/pip install -r requirements.txt # if dependencies changed
sudo systemctl start zenai-ktc-counter zenai-ktc-dashboard
```
---
## 7. Troubleshooting
| Symptom | Things to check |
|---------|-----------------|
| Counter won't start | `journalctl -u zenai-ktc-counter`; verify `MODEL_PATH` exists; RKNN drivers installed |
| No RTSP frames | Ping camera; test with `ffplay <SOURCE>`; check `OPENCV_FFMPEG_CAPTURE_OPTIONS` |
| Dashboard shows 0 count | `STATE_FILE` in `.env` must match between counter and dashboard; check file exists |
| Live video blank | `LIVE_STREAM_ENABLED=true`; path matches `LIVE_STREAM_FRAME_PATH` in both processes |
| Wrong feeder / missed counts | Tune `ZONE_*_FRAC`, `CONF`, ByteTrack thresholds; enable `DEBUG_TRACKING=true` |
| Service keeps restarting | `journalctl -u zenai-ktc-counter -e`; often missing model, bad RTSP URL, or venv not created |
### Manual test (without systemd)
```bash
cd /opt/zenai-ktc-python
source venv/bin/activate
python counter_live_rknn.py # terminal 1
python counter_dashboard.py # terminal 2
```
---
## 8. Optional: reverse proxy
For HTTPS or port 80 access, put nginx in front of the dashboard:
```nginx
server {
listen 80;
server_name counter.example.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off; # required for /api/live-video MJPEG stream
proxy_read_timeout 3600s; # keep long-lived MJPEG connections open
proxy_send_timeout 3600s;
}
}
```
---
## 9. Security notes
- Change `SECRET_KEY` from the default before exposing the dashboard on a network.
- Services currently run as `root` for simplicity on edge devices. For hardened deployments, create a dedicated user, chown `/opt/zenai-ktc-counter`, and update the `User=` / `Group=` lines in the service files.
- Do not commit `.env` — it may contain RTSP credentials.
- Set `FLASK_DEBUG=false` in production.