Compare commits

...
2 Commits
3 changed files with 59 additions and 6 deletions

No files matched your search

+1 -1
View File
@@ -43,7 +43,7 @@ PYTHONNOUSERSITE=1 venv/bin/python recounting_dashboard_upload.py
- **`numpy<2`** is required for `rknn-toolkit-lite2` compatibility. - **`numpy<2`** is required for `rknn-toolkit-lite2` compatibility.
- **Install path in service files is `/opt/bytetrack-counter`** (not the `/opt/jetson-counter` mentioned in README/DEPLOY). The `.env.example` also reflects `/opt/bytetrack-counter`. - **Install path in service files is `/opt/bytetrack-counter`** (not the `/opt/jetson-counter` mentioned in README/DEPLOY). The `.env.example` also reflects `/opt/bytetrack-counter`.
- Service user is **`root`**, not `jetson` (despite README saying otherwise). - Service user is **`root`**, not `jetson` (despite README saying otherwise).
- Two systemd units: `bytetrack-counter.service` + `bytetrack-counter-dashboard.service`. - Three systemd units: `bytetrack-counter.service`, `bytetrack-counter-dashboard.service`, and `bytetrack-recounting-upload-dashboard.service` (upload recounting dashboard, port 5003).
- `counter_live.py` (TensorRT) is Jetson-only and won't work on RK3588. - `counter_live.py` (TensorRT) is Jetson-only and won't work on RK3588.
- **Reset flow**: `POST /api/reset` → deletes state JSON + touches `{SHM_DIR}/.reset`. `batch_store._check_reset_signal()` watches this marker and clears in-memory state on next crossing. - **Reset flow**: `POST /api/reset` → deletes state JSON + touches `{SHM_DIR}/.reset`. `batch_store._check_reset_signal()` watches this marker and clears in-memory state on next crossing.
- **Upload filename contract**: uploads are expected as `batch_XX_YYYYMMDD_HHmmSS.mp4` (XX = batch number, timestamp = date). `recounting_dashboard_upload.py` parses both to query the live API's `/api/day-detail/<YYYY-MM-DD>` for the recorded count. - **Upload filename contract**: uploads are expected as `batch_XX_YYYYMMDD_HHmmSS.mp4` (XX = batch number, timestamp = date). `recounting_dashboard_upload.py` parses both to query the live API's `/api/day-detail/<YYYY-MM-DD>` for the recorded count.
@@ -0,0 +1,34 @@
[Unit]
Description=Edge Counter Recounting Upload Dashboard (Flask, port 5003)
Documentation=file:///opt/bytetrack-counter/DEPLOY.md
After=network-online.target bytetrack-counter-dashboard.service
Wants=network-online.target bytetrack-counter-dashboard.service
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/bytetrack-counter
EnvironmentFile=/opt/bytetrack-counter/.env
Environment=PATH=/opt/bytetrack-counter/venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONNOUSERSITE=1
Environment=FLASK_DEBUG=false
ExecStart=/opt/bytetrack-counter/venv/bin/python recounting_dashboard_upload.py
TimeoutStopSec=15
KillSignal=SIGTERM
Restart=on-failure
RestartSec=5
StartLimitInterval=60s
StartLimitBurst=3
NoNewPrivileges=true
ProtectHome=true
PrivateTmp=false
[Install]
WantedBy=multi-user.target
+24 -5
View File
@@ -8,6 +8,7 @@ import logging
import os import os
import re import re
import shlex import shlex
import signal
import subprocess import subprocess
import threading import threading
import time import time
@@ -74,13 +75,31 @@ def _api_get(base_url, path, default=None):
def _stop_recount_locked(): def _stop_recount_locked():
global _recount_proc global _recount_proc
if _recount_proc: proc = _recount_proc
_recount_proc = None
if proc is None:
return
try:
pgid = os.getpgid(proc.pid)
except (ProcessLookupError, PermissionError):
return
try:
os.killpg(pgid, signal.SIGTERM)
except (ProcessLookupError, PermissionError):
pass
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
try: try:
_recount_proc.kill() os.killpg(pgid, signal.SIGKILL)
_recount_proc.wait(timeout=3) except (ProcessLookupError, PermissionError):
pass
try:
proc.wait(timeout=3)
except Exception: except Exception:
pass pass
_recount_proc = None except Exception:
pass
def _folder_date(filepath, base): def _folder_date(filepath, base):
@@ -179,7 +198,7 @@ def start_recount():
_current_file = upload_path _current_file = upload_path
cmd_str = RECOUNT_CMD.replace("{path}", shlex.quote(str(upload_path))) cmd_str = RECOUNT_CMD.replace("{path}", shlex.quote(str(upload_path)))
try: try:
_recount_proc = subprocess.Popen(cmd_str, shell=True) _recount_proc = subprocess.Popen(cmd_str, shell=True, start_new_session=True)
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Recount started: {cmd_str}") print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Recount started: {cmd_str}")
except Exception as e: except Exception as e:
_current_file = None _current_file = None