2026-08-13 16:23:18 +04:00

99 lines
3.5 KiB
Python

"""
Entry point: ``python -m backend``
Binds 0.0.0.0 and prints every address the dashboard is reachable on, so you can
open it from a phone or tablet on the same Wi-Fi without knowing this machine's
IP in advance.
"""
from __future__ import annotations
import argparse
import sys
from . import netinfo, settings
def main() -> int:
parser = argparse.ArgumentParser(prog="python -m backend",
description="AGIBOT X2 dashboard server")
parser.add_argument("--port", type=int, help="HTTP port (default from config.json)")
parser.add_argument("--host", default=None, help="Bind address (default 0.0.0.0 - all interfaces)")
parser.add_argument("--robot", default=None, help="Robot host or IP; saved to config.json")
parser.add_argument("--domain", type=int, default=None, help="ROS_DOMAIN_ID")
parser.add_argument("--mode", choices=["auto", "ros2", "mock"], default=None,
help="Bridge mode: auto (default), ros2 (require rclpy), mock (simulate)")
parser.add_argument("--reload", action="store_true", help="Auto-reload on source changes")
args = parser.parse_args()
updates = {}
if args.port is not None:
updates["port"] = args.port
if args.robot is not None:
updates["robot_host"] = args.robot
if args.domain is not None:
updates["ros_domain_id"] = args.domain
if args.mode is not None:
updates["bridge_mode"] = args.mode
if updates:
settings.save(updates)
config = settings.load()
host = args.host or config["host"]
port = config["port"]
try:
import uvicorn
except ImportError:
print("uvicorn is not installed. Run: pip install -r requirements.txt", file=sys.stderr)
return 1
name = config.get("dashboard_name") if config.get("advertise_name") else None
detail = netinfo.address_detail()
print()
print(" AGIBOT X2 Dashboard")
print(" " + "-" * 52)
if detail["ip"]:
print(" Open this from a phone, tablet or laptop:")
print(f" http://{detail['ip']}:{port}")
print(f" (live {detail['kind'] or 'network'} address on '{detail['adapter']}')")
else:
print(" No usable network address right now:")
print(f" {detail['reason_text'] or detail['reason']}")
print(" The dashboard is still running; it will pick the address up")
print(" automatically when the network comes back.")
others = [u for u in netinfo.dashboard_urls(port, name)
if u != f"http://{detail['ip']}:{port}"]
if others:
print()
print(" Also reachable at:")
for url in others:
print(f" {url}")
print(" " + "-" * 52)
print(f" robot host {config['robot_host'] or '(not set - use the Settings tab)'}")
print(f" bridge mode {config['bridge_mode']}")
print(f" ROS_DOMAIN_ID {config['ros_domain_id']}")
print(" Open any address above from any device on this network.")
print(flush=True)
uvicorn.run(
"backend.server:app",
host=host,
port=port,
reload=args.reload,
log_level="info",
access_log=False,
# websockets 16.x crashes uvicorn's default WS impl (starlette/anyio
# "cancel scope" error) -> stuck "Connecting". wsproto is a stable,
# isolated WS engine that avoids it without touching the shared
# `websockets` package the voice pipeline depends on.
ws="wsproto",
)
return 0
if __name__ == "__main__":
raise SystemExit(main())