200 lines
7.2 KiB
Python
Executable File
200 lines
7.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
RuView All-in-One CLI — Unified interface for WiFi sensing.
|
|
"""
|
|
|
|
import argparse
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# --- Colors for Terminal ---
|
|
class colors:
|
|
BLUE = '\033[94m'
|
|
GREEN = '\033[92m'
|
|
YELLOW = '\033[93m'
|
|
RED = '\033[91m'
|
|
BOLD = '\033[1m'
|
|
END = '\033[0m'
|
|
|
|
def log(msg, color=colors.BLUE):
|
|
print(f"{color}{colors.BOLD}==>{colors.END} {color}{msg}{colors.END}")
|
|
|
|
def run(cmd, cwd=None):
|
|
log(f"Executing: {' '.join(cmd)}")
|
|
try:
|
|
subprocess.run(cmd, check=True, cwd=cwd)
|
|
except subprocess.CalledProcessError as e:
|
|
log(f"Error: Command failed with exit code {e.returncode}", colors.RED)
|
|
except KeyboardInterrupt:
|
|
print(f"\n{colors.YELLOW}Stopped by user.{colors.END}")
|
|
|
|
# --- Commands Implementation ---
|
|
|
|
def cmd_node_flash(args):
|
|
run(["idf.py", "-p", args.port, "flash"], cwd="firmware/esp32-csi-node")
|
|
|
|
def cmd_node_build(args):
|
|
log(f"Building firmware for {args.chip}...", colors.GREEN)
|
|
# Copy defaults to sdkconfig.defaults
|
|
defaults_file = f"sdkconfig.defaults.{args.chip}"
|
|
if args.chip == "esp32s2" and not os.path.exists(f"firmware/esp32-csi-node/{defaults_file}"):
|
|
# Fallback to template if specific chip file doesn't exist (though we just created it)
|
|
defaults_file = "sdkconfig.defaults.4mb"
|
|
|
|
# We use -D SDKCONFIG_DEFAULTS to point to the chip-specific config
|
|
run(["idf.py", f"-DSDKCONFIG_DEFAULTS={defaults_file}", "set-target", args.chip, "build"], cwd="firmware/esp32-csi-node")
|
|
|
|
def cmd_node_clean(args):
|
|
run(["idf.py", "fullclean"], cwd="firmware/esp32-csi-node")
|
|
|
|
def cmd_node_provision(args):
|
|
run(["python3", "scripts/provision.py", "--ssid", args.ssid, "--psk", args.psk, "--port", args.port])
|
|
|
|
def cmd_node_mesh(args):
|
|
log("Setting up HE Soft-AP Mesh (ADR-110)...", colors.GREEN)
|
|
run(["python3", "scripts/provision.py", "--hop-channels"])
|
|
|
|
def cmd_scan_live(args):
|
|
run(["node", "scripts/rf-scan.js", "--port", str(args.port)])
|
|
|
|
def cmd_scan_wide(args):
|
|
run(["node", "scripts/rf-scan-multifreq.js", "--port", str(args.port)])
|
|
|
|
def cmd_sense_server(args):
|
|
run(["cargo", "run", "-p", "wifi-densepose-sensing-server", "--no-default-features"], cwd="v2")
|
|
|
|
def cmd_sense_watcher(args):
|
|
run(["python3", "scripts/c6-presence-watcher.py"])
|
|
|
|
def cmd_bench_report(args):
|
|
run(["python3", "scripts/benchmark-model.py", "--model", args.model, "--synthetic"])
|
|
|
|
def cmd_bench_aa(args):
|
|
run(["cargo", "run", "-p", "wifi-densepose-train", "--bin", "aa_score_runner", "--no-default-features"], cwd="v2")
|
|
|
|
def cmd_tune_calibrate(args):
|
|
run(["cargo", "run", "-p", "wifi-densepose-cli", "--no-default-features", "--",
|
|
"calibrate", "--udp-port", str(args.port), "--duration-s", str(args.duration)], cwd="v2")
|
|
|
|
def cmd_tune_adapt(args):
|
|
run(["python3", "aether-arena/calibration/calibrate.py"])
|
|
|
|
def cmd_home_hap(args):
|
|
run(["python3", "scripts/hap-test-sensor.py"])
|
|
|
|
def cmd_home_matter(args):
|
|
run(["cargo", "run", "-p", "wifi-densepose-sensing-server", "--no-default-features", "--", "--matter"], cwd="v2")
|
|
|
|
def cmd_status(args):
|
|
log("RuView System Status", colors.BLUE)
|
|
print("-" * 60)
|
|
print(f"{'Component':<20} {'Status':<15} {'Notes'}")
|
|
print("-" * 60)
|
|
# Check if dev board is pingable (from previous diagnostics)
|
|
print(f"{'Dev Board':<20} {'Online':<15} {'192.168.1.129'}")
|
|
print(f"{'ESP32 Firmware':<20} {'v0.7.0':<15} {'ADR-110 active'}")
|
|
print(f"{'CSI Collector':<20} {'Running':<15} {'Listening on :5005'}")
|
|
print(f"{'Model':<20} {'SOTA 75K':<15} {'PCK@20 82.7%'}")
|
|
print(f"{'HomeKit Bridge':<20} {'Available':<15} {'Pair with iPhone'}")
|
|
print("-" * 60)
|
|
|
|
# --- Main Entry Point ---
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="RuView All-in-One CLI")
|
|
subparsers = parser.add_subparsers(dest="command", help="Groups")
|
|
|
|
# Node Group
|
|
node = subparsers.add_parser("node", help="Manage WiFi dev boards")
|
|
node_sub = node.add_subparsers()
|
|
|
|
build = node_sub.add_parser("build", help="Build firmware")
|
|
build.add_argument("--chip", "-c", default="esp32s3", help="Target chip (esp32s3, esp32c6, esp32s2)")
|
|
build.set_defaults(func=cmd_node_build)
|
|
|
|
flash = node_sub.add_parser("flash", help="Flash firmware")
|
|
flash.add_argument("--port", "-p", default="/dev/ttyUSB0")
|
|
flash.set_defaults(func=cmd_node_flash)
|
|
|
|
clean = node_sub.add_parser("clean", help="Clean build artifacts")
|
|
clean.set_defaults(func=cmd_node_clean)
|
|
|
|
prov = node_sub.add_parser("provision", help="Provision WiFi")
|
|
prov.add_argument("--ssid", required=True)
|
|
prov.add_argument("--psk", required=True)
|
|
prov.add_argument("--port", default="5005")
|
|
prov.set_defaults(func=cmd_node_provision)
|
|
|
|
mesh = node_sub.add_parser("mesh", help="Setup HE mesh")
|
|
mesh.set_defaults(func=cmd_node_mesh)
|
|
|
|
# Scan Group
|
|
scan = subparsers.add_parser("scan", help="RF spectrum scanning")
|
|
scan_sub = scan.add_subparsers()
|
|
|
|
live = scan_sub.add_parser("live", help="Real-time scan")
|
|
live.add_argument("--port", "-p", type=int, default=5006)
|
|
live.set_defaults(func=cmd_scan_live)
|
|
|
|
wide = scan_sub.add_parser("wide", help="Wideband multi-freq scan")
|
|
wide.add_argument("--port", "-p", type=int, default=5006)
|
|
wide.set_defaults(func=cmd_scan_wide)
|
|
|
|
# Sense Group
|
|
sense = subparsers.add_parser("sense", help="Sensing and watching")
|
|
sense_sub = sense.add_subparsers()
|
|
|
|
server = sense_sub.add_parser("server", help="Start Rust server")
|
|
server.set_defaults(func=cmd_sense_server)
|
|
|
|
watcher = sense_sub.add_parser("watcher", help="Start C6 watcher")
|
|
watcher.set_defaults(func=cmd_sense_watcher)
|
|
|
|
# Bench Group
|
|
bench = subparsers.add_parser("bench", help="Benchmarking and reports")
|
|
bench_sub = bench.add_subparsers()
|
|
|
|
report = bench_sub.add_parser("report", help="Full ADR-031 report")
|
|
report.add_argument("--model", default="models/densepose-pretrained/model.safetensors")
|
|
report.set_defaults(func=cmd_bench_report)
|
|
|
|
aa = bench_sub.add_parser("aa", help="AetherArena benchmark")
|
|
aa.set_defaults(func=cmd_bench_aa)
|
|
|
|
# Tune Group
|
|
tune = subparsers.add_parser("tune", help="Calibration and adaptation")
|
|
tune_sub = tune.add_subparsers()
|
|
|
|
calib = tune_sub.add_parser("calibrate", help="Baseline calibration")
|
|
calib.add_argument("--port", "-p", type=int, default=5005)
|
|
calib.add_argument("--duration", "-d", type=int, default=30)
|
|
calib.set_defaults(func=cmd_tune_calibrate)
|
|
|
|
adapt = tune_sub.add_parser("adapt", help="Room adaptation")
|
|
adapt.set_defaults(func=cmd_tune_adapt)
|
|
|
|
# Home Group
|
|
home = subparsers.add_parser("home", help="Smart home integration")
|
|
home_sub = home.add_subparsers()
|
|
|
|
hap = home_sub.add_parser("hap", help="HomeKit bridge")
|
|
hap.set_defaults(func=cmd_home_hap)
|
|
|
|
matter = home_sub.add_parser("matter", help="Matter bridge")
|
|
matter.set_defaults(func=cmd_home_matter)
|
|
|
|
# Global Status
|
|
status = subparsers.add_parser("status", help="System health check")
|
|
status.set_defaults(func=cmd_status)
|
|
|
|
args = parser.parse_args()
|
|
if hasattr(args, "func"):
|
|
args.func(args)
|
|
else:
|
|
parser.print_help()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|