Offline-installable bundle (wheelhouse + model + source) built on a machine with internet and installed on the air-gapped Pi with --no-index (zero fetches), plus a systemd unit (auto-restart, device access, hardening) and env template. Runs the package from source via python -m edge (no offline build backend). Drift-guard test keeps the env template in sync with what the daemon reads and rejects inline comments that systemd EnvironmentFile= would fold into values. |
||
|---|---|---|
| .. | ||
| bundle | ||
| systemd | ||
| README.md | ||
Edge deployment (Raspberry Pi 5, air-gapped / 폐쇄망)
Offline-installable bundle + systemd unit for the move-detect edge daemon.
The bundle is fully self-contained (all wheels + pose model + source): the Pi
performs zero network fetches at install or run time. The only runtime
network use is the cloud POST / config-poll / heartbeat, and even that tolerates
being offline (events buffer in the local sqlite queue and flush on reconnect).
Scope: this covers the CPU MoveNet + USB (UVC) webcam path — the one the daemon wires today (
edge/daemon.py:main) and the one verified end-to-end. Hailo-8 acceleration (edge/adapters/hailo_pose.py) and the CSI camera (edge/adapters/picamera_source.py) are separate device-validated paths — seedocs/hardware-bringup.md.
Files
| File | Runs on | Purpose |
|---|---|---|
bundle/build_offline_bundle.sh |
build machine (has internet) | downloads wheels + model, stages source, emits one tarball |
bundle/install_offline.sh |
the Pi (no internet) | venv + --no-index install, systemd unit, service account |
systemd/move-detect-edge.service |
the Pi | the daemon unit (auto-restart, device access, hardening) |
systemd/move-detect-edge.env.example |
the Pi | env template → /etc/move-detect/edge.env |
1. Build the bundle (on a machine WITH internet)
Most reliable: build on an aarch64 host (a Pi 5, or an arm64 CI runner) so the downloaded wheels match the target exactly:
deploy/bundle/build_offline_bundle.sh # native aarch64 wheels
From an x86 box you can attempt a cross build (best-effort — onnxruntime/opencv wheel tags may not resolve; if it fails, build natively):
deploy/bundle/build_offline_bundle.sh --cross # target aarch64 / cp311
Output: dist/move-detect-edge-bundle-aarch64-cp311.tar.gz (+ MANIFEST.txt
listing the bundled wheels). This single file crosses the air gap.
2. Transfer + install (on the air-gapped Pi)
Copy the tarball across the gap (USB, one-way transfer, etc.), then:
tar xzf move-detect-edge-bundle-aarch64-cp311.tar.gz
cd move-detect-edge-bundle
sudo ./install_offline.sh
The installer: creates the movedetect service account (in video/render/
plugdev/hailo groups), lays down source + model under /opt/move-detect,
builds a venv and installs the bundled wheels with --no-index, verifies the
package imports, seeds /etc/move-detect/edge.env, and installs the systemd unit.
3. Configure + start
sudo nano /etc/move-detect/edge.env # DEVICE_ID, DEVICE_SECRET, CAFE24_URL, ...
sudo systemctl enable --now move-detect-edge
journalctl -u move-detect-edge -f
DEVICE_ID/DEVICE_SECRET must match a devices row in the cloud (see
cloud/docs/cloud-deploy.md §6). MOVENET_ONNX should point at the bundled
model (/opt/move-detect/models/movenet_lightning.onnx).
4. Verify the air gap (do this before trusting a build)
- On a host with networking disabled,
install_offline.shcompletes — the--no-indexinstalls prove nothing is fetched. If pip tries to reach PyPI, a wheel is missing from the bundle: rebuild (step 1) natively. - Step [4/6] of the installer prints
edge import OK(onnxruntime + cv2 + numpy + requests all import from the venv). systemctl status move-detect-edgeisactive (running); the log shows frames processed and (if the cloud is reachable) heartbeats.- Pull the network cable → events keep queueing (
QUEUE_DBgrows) → restore → the queue flushes. (End-to-end behavior verified in the edge e2e harness.)
Not bundled (by design)
- MySQL / the cloud app — a separate host; see
cloud/docs/cloud-deploy.md. - HailoRT +
yolov8s_pose.hef— the Hailo runtime and HEF are installed via Hailo's own Pi packages; the CPU MoveNet path here needs neither.