#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────── # Deploy marionette to Reachy Mini Wireless and start it via the daemon. # # This is a development tool: it rsyncs your local source code to the # robot's site-packages (the same place the dashboard installs to), # then starts the app through the daemon API (same as clicking "Start" # on the dashboard). Logs stream live to your terminal. # # PREREQUISITES: # 1. Passwordless SSH access to the robot: # ssh-copy-id pollen@reachy-mini.local (password: root) # # 2. The reachy-mini-daemon must be running on the robot. # It starts automatically on boot. If stopped: # ssh pollen@reachy-mini.local 'systemctl restart reachy-mini-daemon.service' # # 3. The robot must be powered on and on the same network as your laptop. # If reachy-mini.local doesn't resolve, pass the IP address instead. # # WIRELESS ONLY: # This script targets the Wireless version's shared venv at # /venvs/apps_venv/ with Python 3.12. The Lite version uses a # different venv layout — this script will NOT work on Lite as-is. # # HOW IT WORKS: # 1. Checks the daemon is running (systemctl is-active) # 2. Rsyncs marionette/ into site-packages (~1 second) # 3. Stops any currently running app (POST /api/apps/stop-current-app) # 4. Starts marionette via daemon (POST /api/apps/start-app/marionette) # 5. Tails journalctl for live log output # # Ctrl+C detaches from logs — the app keeps running on the robot. # You can also stop it from the dashboard, or with ./stop_app.sh. # # USAGE: # ./deploy_wireless.sh # default: reachy-mini.local # ./deploy_wireless.sh 192.168.1.42 # custom IP # ./deploy_wireless.sh --sync-only # sync without starting # ───────────────────────────────────────────────────────────────────── set -euo pipefail SYNC_ONLY=false HOST="reachy-mini.local" for arg in "$@"; do case "$arg" in --sync-only) SYNC_ONLY=true ;; *) HOST="$arg" ;; esac done USER="pollen" SITE_PACKAGES="/venvs/apps_venv/lib/python3.12/site-packages" REMOTE="${USER}@${HOST}" TARGET="${REMOTE}:${SITE_PACKAGES}/marionette/" DAEMON_API="http://127.0.0.1:8000/api/apps" # Resolve the directory this script lives in (the marionette project root) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SOURCE="${SCRIPT_DIR}/marionette/" # ── 1. Check daemon is running ─────────────────────────────────────── echo "==> Checking daemon on ${HOST}..." if ! ssh -o ConnectTimeout=5 "${REMOTE}" \ "systemctl is-active --quiet reachy-mini-daemon" 2>/dev/null; then echo " ERROR: reachy-mini-daemon is not running on ${HOST}." echo " Start it with: ssh ${REMOTE} 'sudo systemctl start reachy-mini-daemon'" exit 1 fi echo " Daemon is running." # ── 2. Rsync source to site-packages ───────────────────────────────── # This overwrites the installed package with your local source. # The dashboard can still manage the app normally afterwards. echo "==> Syncing marionette/ to ${HOST}..." rsync -az --delete \ --exclude '__pycache__' \ --exclude '*.pyc' \ "$SOURCE" "$TARGET" echo " Sync complete." if $SYNC_ONLY; then echo "Done (sync only)." exit 0 fi # ── 3. Stop any currently running app ───────────────────────────────── # Uses the same daemon API as the dashboard's "Stop" button. # This stops WHATEVER app is running (not just marionette). echo "==> Stopping current app (if any)..." ssh "${REMOTE}" "curl -sf -X POST ${DAEMON_API}/stop-current-app >/dev/null 2>&1 || true" sleep 1 # ── 4. Start marionette via daemon API ──────────────────────────────── # Same as clicking "Start" on the dashboard. The daemon launches # marionette as a managed subprocess with the correct venv and # ReachyMini connection context. echo "==> Starting marionette via daemon..." RESP=$(ssh "${REMOTE}" "curl -sf -X POST ${DAEMON_API}/start-app/marionette 2>/dev/null") if [ $? -ne 0 ]; then echo " ERROR: Failed to start marionette via daemon API." echo " Response: ${RESP}" exit 1 fi echo " Started." echo "" echo "Web UI: http://${HOST}:8042" echo "" # ── 5. Tail logs live ───────────────────────────────────────────────── # Streams the daemon's journal output. Marionette's stdout/stderr # appears here because it runs as a child of the daemon. # Ctrl+C detaches from logs — the app keeps running on the robot. echo "==> Tailing logs (Ctrl+C to detach — app keeps running)..." echo "" ssh "${REMOTE}" "journalctl -u reachy-mini-daemon -f --no-hostname -o cat" 2>/dev/null || true