| |
| """Discover Nova API configuration from your instance. |
| |
| This script connects to your Nova instance and discovers available |
| controllers and motion groups to help you configure the environment variables. |
| |
| Requirements: |
| - python-dotenv: pip install python-dotenv |
| """ |
|
|
| import json |
| import os |
| import sys |
| import urllib.request |
| from pathlib import Path |
|
|
| try: |
| from dotenv import load_dotenv |
| except ImportError: |
| print("Error: python-dotenv is required") |
| print("Install with: pip install python-dotenv") |
| sys.exit(1) |
|
|
|
|
| def request_json(url, access_token): |
| """Make a GET request to the Nova API.""" |
| request = urllib.request.Request(url) |
| request.add_header("Authorization", f"Bearer {access_token}") |
| request.add_header("Content-Type", "application/json") |
| try: |
| with urllib.request.urlopen(request, timeout=10) as response: |
| body = response.read().decode("utf-8") |
| return json.loads(body) if body else {} |
| except urllib.error.HTTPError as exc: |
| body = exc.read().decode("utf-8") if exc.fp else "" |
| print(f"Error: Nova API returned status {exc.code}") |
| print(f"Response: {body}") |
| return None |
|
|
|
|
| def main(): |
| |
| env_local = Path("nova-sim/.env.local") |
| env_file = Path("nova-sim/.env") |
|
|
| if env_local.exists(): |
| load_dotenv(env_local) |
| print(f"Loaded configuration from {env_local}") |
| elif env_file.exists(): |
| load_dotenv(env_file) |
| print(f"Loaded configuration from {env_file}") |
| else: |
| print("Error: No .env or .env.local file found") |
| print("Create one with at least NOVA_INSTANCE_URL and NOVA_ACCESS_TOKEN") |
| return 1 |
|
|
| |
| instance_url = os.getenv("NOVA_INSTANCE_URL") or os.getenv("NOVA_API") |
| access_token = os.getenv("NOVA_ACCESS_TOKEN") |
| cell_id = os.getenv("NOVA_CELL_ID", "cell") |
|
|
| if not instance_url: |
| print("Error: NOVA_INSTANCE_URL (or NOVA_API) not set") |
| return 1 |
|
|
| if not access_token: |
| print("Error: NOVA_ACCESS_TOKEN not set") |
| return 1 |
|
|
| print(f"\nConnecting to Nova instance: {instance_url}") |
| print(f"Cell ID: {cell_id}") |
| print() |
|
|
| |
| print("Fetching controllers...") |
| controllers_url = f"{instance_url}/api/v2/cells/{cell_id}/controllers" |
| controllers_data = request_json(controllers_url, access_token) |
|
|
| if not controllers_data: |
| return 1 |
|
|
| controllers = controllers_data.get("instances", []) |
| if not controllers: |
| print("No controllers found") |
| return 1 |
|
|
| print(f"Found {len(controllers)} controller(s):") |
| print() |
|
|
| for controller in controllers: |
| controller_id = controller.get("controller", "unknown") |
| print(f"Controller ID: {controller_id}") |
|
|
| |
| motion_groups_url = f"{instance_url}/api/v2/cells/{cell_id}/controllers/{controller_id}/motion-groups" |
| motion_groups_data = request_json(motion_groups_url, access_token) |
|
|
| if not motion_groups_data: |
| continue |
|
|
| motion_groups = motion_groups_data.get("motion_groups", []) |
| print(f" Motion groups: {len(motion_groups)}") |
|
|
| for mg in motion_groups: |
| mg_id = mg.get("motion_group", "unknown") |
| model = mg.get("model_from_controller", "unknown") |
| name = mg.get("name_from_controller", "") |
|
|
| print(f" - ID: {mg_id}") |
| print(f" Model: {model}") |
| if name: |
| print(f" Name: {name}") |
|
|
| |
| desc_url = f"{instance_url}/api/v2/cells/{cell_id}/controllers/{controller_id}/motion-groups/{mg_id}/description" |
| desc_data = request_json(desc_url, access_token) |
|
|
| if desc_data: |
| tcps = desc_data.get("tcps", {}) |
| if tcps: |
| print(f" Available TCPs: {', '.join(tcps.keys())}") |
| print() |
|
|
| |
| print("\n" + "=" * 60) |
| print("RECOMMENDED CONFIGURATION") |
| print("=" * 60) |
|
|
| if controllers: |
| controller = controllers[0] |
| controller_id = controller.get("controller", "unknown") |
|
|
| |
| motion_groups_url = f"{instance_url}/api/v2/cells/{cell_id}/controllers/{controller_id}/motion-groups" |
| motion_groups_data = request_json(motion_groups_url, access_token) |
|
|
| if motion_groups_data: |
| motion_groups = motion_groups_data.get("motion_groups", []) |
| if motion_groups: |
| mg = motion_groups[0] |
| mg_id = mg.get("motion_group", "unknown") |
| model = mg.get("model_from_controller", "unknown") |
|
|
| print("\nAdd these to your .env.local file:") |
| print(f""" |
| NOVA_INSTANCE_URL={instance_url} |
| NOVA_ACCESS_TOKEN={access_token[:20]}... # (your full token) |
| NOVA_CELL_ID={cell_id} |
| NOVA_CONTROLLER_ID={controller_id} |
| NOVA_MOTION_GROUP_ID={mg_id} |
| NOVA_MOTION_GROUP_MODEL={model} |
| NOVA_TCP_NAME=Flange |
| NOVA_RESPONSE_RATE_MS=200 |
| """) |
|
|
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| sys.exit(main()) |
|
|