#!/usr/bin/env python3 """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(): # Try to load from .env.local first, then .env 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 # Get configuration from environment 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() # Fetch controllers 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}") # Fetch motion groups for this controller 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}") # Fetch motion group description 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() # Generate recommended .env configuration print("\n" + "=" * 60) print("RECOMMENDED CONFIGURATION") print("=" * 60) if controllers: controller = controllers[0] controller_id = controller.get("controller", "unknown") # Get motion groups for first controller 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())