Files
zenai-kpc-python/DEPLOY.md
T

7.2 KiB

ZenAI KPC Counter — Edge Deployment Guide

Production deployment for RK3588 (or compatible RKNN NPU) edge devices running:

Component Script systemd unit
RTSP counter (RKNN + ByteTrack) counter_live_rknn.py zenai-kpc-counter.service
Web dashboard (Flask) counter_dashboard.py zenai-kpc-dashboard.service

Both processes share a single .env file and read/write the same SQLite database and state JSON.


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

sudo apt update
sudo apt install -y python3 python3-venv python3-pip ffmpeg libgl1

ffmpeg is required for low-latency RTSP capture via OpenCV and for session MP4 recording (RECORD_VIDEO=true). libgl1 is often needed for opencv-python on headless systems.

RKNN model

Export or copy your .rknn model to the device, e.g.:

/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:

/opt/zenai-kpc-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-kpc-counter/         # persistent runtime data (created automatically)
├── counter.db                  # SQLite daily records
├── current_counter.json        # live counting-day state
├── snapshots/                  # crossing/detect JPEGs (if enabled)
└── crossings.csv               # optional per-event CSV

/opt/models/                    # RKNN models (deploy separately)
/dev/shm/zenai-kpc-counter/     # live JPEG frame for dashboard video (tmpfs)

3. Install application

3.1 Copy code to the device

sudo mkdir -p /opt/zenai-kpc-python
sudo rsync -av --exclude venv --exclude .env --exclude __pycache__ \
  ./ /opt/zenai-kpc-python/
# Or: sudo git clone <repo-url> /opt/zenai-kpc-python

3.2 Create virtual environment and install dependencies

cd /opt/zenai-kpc-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

cd /opt/zenai-kpc-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)
LINE_Y1_FRAC / LINE_Y2_FRAC Counting line positions (tune per camera)
SECRET_KEY Random string for Flask sessions

Ensure STATE_FILE and DB_PATH both live under /opt/zenai-kpc-counter/ so data survives reboots (avoid /tmp in production).

3.4 Create data directories (optional — app creates most paths automatically)

sudo mkdir -p /opt/zenai-kpc-counter /opt/models /dev/shm/zenai-kpc-counter

4. Install systemd services

cd /opt/zenai-kpc-python
sudo cp zenai-kpc-counter.service zenai-kpc-dashboard.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable zenai-kpc-counter zenai-kpc-dashboard
sudo systemctl start zenai-kpc-counter
sudo systemctl start zenai-kpc-dashboard

The dashboard unit starts after the counter unit (After=zenai-kpc-counter.service).

Verify

systemctl status zenai-kpc-counter
systemctl status zenai-kpc-dashboard
journalctl -u zenai-kpc-counter -f

Open the dashboard in a browser:

http://<device-ip>:5000

(Port is set by DASHBOARD_PORT in .env, default 5000.)


5. Operations

Restart after config change

sudo systemctl restart zenai-kpc-counter
sudo systemctl restart zenai-kpc-dashboard

View logs

journalctl -u zenai-kpc-counter -n 100 --no-pager
journalctl -u zenai-kpc-dashboard -n 100 --no-pager

Stop services

sudo systemctl stop zenai-kpc-dashboard zenai-kpc-counter

The counter handles SIGTERM gracefully — it finishes the current frame, persists state to SQLite, then exits.

Update application code

cd /opt/zenai-kpc-python
sudo systemctl stop zenai-kpc-dashboard zenai-kpc-counter
# rsync or git pull new code
sudo ./venv/bin/pip install -r requirements.txt   # if dependencies changed
sudo systemctl start zenai-kpc-counter zenai-kpc-dashboard

6. Troubleshooting

Symptom Things to check
Counter won't start journalctl -u zenai-kpc-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; if using nginx, set proxy_read_timeout (see §7)
Wrong counts Tune LINE_Y1_FRAC/LINE_Y2_FRAC, CONF, ByteTrack thresholds; enable DEBUG_TRACKING=true temporarily
Service keeps restarting journalctl -u zenai-kpc-counter -e; often missing model, bad RTSP URL, or venv not created

Manual test (without systemd)

cd /opt/zenai-kpc-python
source venv/bin/activate
python counter_live_rknn.py    # terminal 1
python counter_dashboard.py    # terminal 2

7. Optional: reverse proxy

For HTTPS or port 80 access, put nginx in front of the dashboard:

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;
    }
}

The live JPEG at LIVE_STREAM_FRAME_PATH can also be served statically by nginx if you prefer not to use the Flask MJPEG endpoint.


8. 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-kpc-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.