# sanad_api_g1 — copy to .env and fill in. docker compose reads it automatically. # ONE agent = telemetry + map + logs + alerts + remote (see fleet/README.md). # ── fleet server (REQUIRED — YS Lootah gives you these two) ────────────────── SERVER_URL=https://fleet.example.com DEVICE_TOKEN=REPLACE_WITH_DEVICE_TOKEN # ── identity ───────────────────────────────────────────────────────────────── # The robot's REAL Unitree serial — keys the robot on the server ({sn} routes). SN=E21D6000PB89GF88 # Friendly display name shown on the dashboard (default _). ROBOT_NAME=g1_58 ROBOT_BRAND=unitree ROBOT_TYPE=humanoid ROBOT_MODEL=g1 # web_nav3 robot name: the maps subdir (//*.db) + X-Robot-Name. ROBOT=sanad # Optional: Sanad data dir whose size is reported in storage (as /host/ # when the installer's read-only /:/host mount is used). Empty = omit. STORAGE_DATA_PATH= # ── DDS (reading robot state) ──────────────────────────────────────────────── # Use the interface that sees the robot's DDS traffic (G1 backpack: eth0). DDS_INTERFACE=eth0 DDS_DOMAIN=0 # Which NIC's MAC to report as the robot identity (defaults to DDS_INTERFACE). # MAC_INTERFACE=eth0 # ── status / position options ──────────────────────────────────────────────── # Read the loco FSM for a richer status (READ-ONLY GET RPC, never commands # motion). 0 = derive status from battery + joint motion only (safe default). G1_READ_FSM=0 # Position source: odom (rt/lf/odommodestate over DDS) | rosbridge | none. G1_POSITION_SOURCE=odom ROSBRIDGE_URL=ws://127.0.0.1:9090 # ── fault thresholds ───────────────────────────────────────────────────────── LOW_SOC=50 MOTOR_TEMP_MAX=85 # ── cadence / transport ────────────────────────────────────────────────────── POLL_INTERVAL=2 VERIFY_TLS=1 HTTP_TIMEOUT=10 # ── map sync (uploaded ONCE per content; status shown in telemetry "map") ──── # The installer mounts the robot's real maps dir at /data/maps (probed on the # robot: rtabmap*.db / slam_toolbox yaml+pgm sets). Fallback = agent's own dir. MAPS_DIR=/data/maps # Extra map roots (colon-separated container paths) — Nav2/Pudu deploy maps # (map.pgm + map.yaml). The installer mounts the robot's *_nav2_docker/maps # here; safe to leave set even when nothing is mounted (missing dirs skipped). EXTRA_MAP_DIRS=/data/nav2_maps DATA_DIR=/data/web_data STATE_DIR=/data/state # Which maps to upload: all | active | newest. active needs WEB_NAV3_URL. MAP_SELECT=all # Optional — only used to learn which map is ACTIVE (MAP_SELECT=active). WEB_NAV3_URL=http://127.0.0.1:8765 # Optional legacy per-robot places file (older sanad setups). Leave blank if # each map already has its own places under DATA_DIR//places/. # LEGACY_PLACES=/data/legacy/places.json MAP_UPLOAD_MODE=multipart MAP_POLL_INTERVAL=30 # Skip .db maps larger than this (the prod server 413s at ~8 MB). Raster # (pgm+yaml) maps are tiny and never skipped. MAP_MAX_UPLOAD_MB=7 # ── logs + alerts ───────────────────────────────────────────────────────────── # agent log lines shipped to /{sn}/logs every LOGS_INTERVAL; new faults POSTed # to /{sn}/alert immediately (rising edge). LOGS_INTERVAL=60 # ── project logs (shared alongside agent logs) ─────────────────────────────── # auto (default) = find a RUNNING Sanad project container (sanadr1, sanad-p4, # sanad*) via the /host mount and tail its docker json-log, labeled # "-logs" in the shipped lines; telemetry shows project_logs (null=none). # Or pin a container name / an explicit log file (PROJECT_LOG_PATH, via /host). PROJECT_LOG_CONTAINER=auto PROJECT_LOG_PATH= PROJECT_LOG_LABEL= # ── remote dashboard (register the Sanad web UI for the fleet to embed) ─────── # The agent probes these ports on the robot, finds the Sanad dashboard, and # POSTs its URL to /{sn}/remote (kind=web) — no changes to the Sanad app. REMOTE_ENABLE=1 REMOTE_PORTS=8001,8014,8011,8012,8013,8000,8080 REMOTE_KIND=web # REMOTE_HOST= # default: the robot's primary LAN IP (fleet-reachable) # REMOTE_URL= # pin an explicit URL (e.g. a public reverse-tunnel) — wins over discovery REMOTE_INTERVAL=60 # ── control panel (READ-ONLY loco mode; remote SWITCH is off by design) ─────── # The agent reads the Sanad dashboard's /api/controller/status (no DDS, no # motion) and reports the current mode (G1: running/lock/squat/…) + the # switchable set in telemetry.control. CONTROL_ENABLE stays 0: remote mode- # SWITCHING is deliberately NOT built (it commands motion and can drop the robot; # switching is done in person on the Sanad dashboard). Leave URL blank to use the # auto-discovered dashboard port. CONTROL_STATUS_URL= CONTROL_ENABLE=0 # ── log-driven alerts (Gemini billing + any robot ERROR) ───────────────────── # The agent scans the robot's project (sanadr1) logs; each NEW matching signature # fires an alert (deduped per ALERT_LOG_COOLDOWN). "CODE=regex" entries split by ;; # ALERT_LOG_PATTERNS=GEMINI_BILLING=prepayment credits.{0,40}deplet|Please go to AI Studio|Failed to connect to Gemini;;ROBOT_ERROR=\bERROR\b|Traceback|Exception|CRITICAL ALERT_LOG_COOLDOWN=300 ALERT_SCAN_INTERVAL=10