Spaces:
Running
Running
| # Install the Reachy Web dashboard as a systemd service that starts at boot, | |
| # so http://<robot>.local:8042 is up the moment the robot is, no SSH needed. | |
| # | |
| # ./setup.sh # install + enable + start the boot service | |
| # ./setup.sh --uninstall # remove it | |
| # | |
| # Run it as your normal user (e.g. pollen), NOT as root: it calls sudo only for | |
| # the parts that need it (writing the unit, enabling it), and the dashboard must | |
| # run as you β your venv, your HOME, your HF session. | |
| set -euo pipefail | |
| SELF_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| SERVICE="reachy-web.service" | |
| UNIT="/etc/systemd/system/$SERVICE" | |
| DAEMON_UNIT="reachy-mini-daemon.service" | |
| # Same test run.sh uses: the daemon's OWN systemd unit is the unambiguous marker | |
| # (not port 8000, which anything could hold); failing that, the robot's brain is | |
| # always a Raspberry Pi, a laptop is not. | |
| on_robot() { | |
| if command -v systemctl >/dev/null 2>&1 \ | |
| && systemctl cat "$DAEMON_UNIT" >/dev/null 2>&1; then | |
| return 0 | |
| fi | |
| grep -aqi "raspberry pi" /proc/device-tree/model 2>/dev/null | |
| } | |
| uninstall() { | |
| echo "ποΈ Removing $SERVICEβ¦" | |
| sudo systemctl disable --now "$SERVICE" 2>/dev/null || true | |
| sudo rm -f "$UNIT" | |
| sudo systemctl daemon-reload | |
| echo "β Done β the dashboard will no longer start at boot." | |
| } | |
| case "${1:-}" in | |
| --uninstall|-u|remove) uninstall; exit 0 ;; | |
| "" ) ;; | |
| * ) echo "usage: $0 [--uninstall]" >&2; exit 2 ;; | |
| esac | |
| if [ "$(id -u)" = 0 ]; then | |
| echo "β Run setup.sh as your normal user (e.g. pollen), not as root." >&2 | |
| echo " It will sudo the parts that need it. The dashboard must run as you." >&2 | |
| exit 1 | |
| fi | |
| if ! on_robot; then | |
| # Not detected as the robot. Don't just refuse β explain, and let the user | |
| # override (the detection can be wrong: a dev Pi, an unusual image). Default No. | |
| cat <<EOF | |
| β οΈ This does not look like a Reachy robot: no $DAEMON_UNIT, and not a Raspberry Pi. | |
| setup.sh installs a systemd service that launches the Reachy Web dashboard | |
| at every boot. That is meant for the robot itself β installing it HERE would | |
| add a boot service to THIS machine (and it needs systemd + sudo to work). | |
| On a laptop you normally just run ./run.sh when you want the dashboard. | |
| EOF | |
| printf " Install the boot service here anyway? [y/N] " | |
| reply="" | |
| read -r reply 2>/dev/null </dev/tty || true # no controlling tty β stays No | |
| case "$reply" in | |
| y|Y|yes|YES|Yes) echo " β continuing." ;; | |
| *) echo " β aborted, nothing changed."; exit 1 ;; | |
| esac | |
| fi | |
| RUN_USER="$(id -un)" | |
| # 0) audio tools for the sound waveforms and server-side listen. The daemon reads | |
| # audio via the pulsectl PYTHON lib, so a robot can have a working sound stack | |
| # yet no CLI tools β which audio.py needs. `pactl` (pulseaudio-utils) finds the | |
| # mic/speaker; `pw-record` (pipewire-bin) is what actually CAPTURES (this robot | |
| # is PipeWire and parec read nothing from its suspended sources). Best-effort. | |
| if ! command -v pactl >/dev/null 2>&1 || ! command -v pw-record >/dev/null 2>&1; then | |
| echo "π Installing audio tools (pactl + pw-record, for the sound waveforms)β¦" | |
| sudo apt-get install -y pulseaudio-utils pipewire-bin 2>/dev/null \ | |
| || echo " (skipped: no apt or offline β install pulseaudio-utils pipewire-bin by hand)" | |
| fi | |
| # 1) build the venv + install deps ONCE, now, while we (probably) have internet β | |
| # so the boot service can skip the online reinstall every boot (a robot may | |
| # boot offline). run.sh --install-only does exactly the install, then stops. | |
| echo "π Preparing the virtualenv and dependencies (once)β¦" | |
| REACHY_WEB_INSTALL_ONLY=1 "$SELF_DIR/run.sh" | |
| # 2) write the unit. It runs run.sh as you, after the network and the daemon | |
| # (soft: it still starts if the daemon unit is absent). Headless boot flags: | |
| # no browser, no reinstall, and DON'T wake the robot just because the Pi | |
| # powered on β leave it exactly as it is (the UI wakes it on demand). | |
| echo "π Writing $UNITβ¦" | |
| sudo tee "$UNIT" >/dev/null <<EOF | |
| [Unit] | |
| Description=Reachy Web dashboard | |
| Documentation=https://huggingface.co/spaces/Domotick/reachy_web | |
| After=network-online.target $DAEMON_UNIT | |
| Wants=network-online.target $DAEMON_UNIT | |
| [Service] | |
| Type=simple | |
| User=$RUN_USER | |
| WorkingDirectory=$SELF_DIR | |
| ExecStart=/usr/bin/env bash $SELF_DIR/run.sh | |
| Restart=on-failure | |
| RestartSec=5 | |
| Environment=REACHY_WEB_NO_BROWSER=1 | |
| Environment=REACHY_WEB_SKIP_INSTALL=1 | |
| Environment=REACHY_WEB_WAKE_ON_START=0 | |
| Environment=REACHY_WEB_SLEEP_ON_EXIT=0 | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| # 3) enable at boot + start now | |
| echo "π§ Enabling and starting the serviceβ¦" | |
| sudo systemctl daemon-reload | |
| sudo systemctl enable --now "$SERVICE" | |
| echo | |
| echo "β Installed. The dashboard now starts at every boot, as $RUN_USER." | |
| echo " status : systemctl status $SERVICE" | |
| echo " logs : journalctl -u $SERVICE -f (or $SELF_DIR/logs/run.log)" | |
| echo " stop : sudo systemctl stop $SERVICE" | |
| echo " remove : $0 --uninstall" | |
| echo | |
| echo "It boots WITHOUT waking the robot (REACHY_WEB_WAKE_ON_START=0); wake it" | |
| echo "from the UI, or set that to 1 in $UNIT if you want it awake on boot." | |