| |
| """Discover Nova API configuration - simple version without dependencies.""" |
|
|
| import json |
| import os |
| import sys |
| import urllib.request |
| from pathlib import Path |
|
|
|
|
| def load_env_file(filepath): |
| """Simple .env file loader.""" |
| env_vars = {} |
| if not filepath.exists(): |
| return env_vars |
|
|
| with open(filepath, 'r') as f: |
| for line in f: |
| line = line.strip() |
| if line and not line.startswith('#') and '=' in line: |
| key, value = line.split('=', 1) |
| env_vars[key.strip()] = value.strip() |
| return env_vars |
|
|
|
|
| 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 |
| except Exception as exc: |
| print(f"Error: {exc}") |
| return None |
|
|
|
|
| def main(): |
| |
| env_local = Path("nova-sim/.env.local") |
| env_file = Path("nova-sim/.env") |
|
|
| env_vars = {} |
| if env_local.exists(): |
| env_vars = load_env_file(env_local) |
| print(f"Loaded configuration from {env_local}") |
| elif env_file.exists(): |
| env_vars = load_env_file(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 = env_vars.get("NOVA_INSTANCE_URL") or env_vars.get("NOVA_API") |
| access_token = env_vars.get("NOVA_ACCESS_TOKEN") |
| cell_id = env_vars.get("NOVA_CELL_ID", "cell") |
|
|
| if not instance_url: |
| print("Error: NOVA_INSTANCE_URL (or NOVA_API) not set in .env file") |
| return 1 |
|
|
| if not access_token: |
| print("Error: NOVA_ACCESS_TOKEN not set in .env file") |
| 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 |
|
|
| |
| if isinstance(controllers_data, list): |
| controllers = controllers_data |
| else: |
| 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: |
| |
| if isinstance(controller, str): |
| controller_id = controller |
| else: |
| controller_id = controller.get("controller", "unknown") |
| print(f"Controller ID: {controller_id}") |
|
|
| |
| motion_groups_url = f"{instance_url}/api/v2/cells/{cell_id}/motion-groups" |
| motion_groups_data = request_json(motion_groups_url, access_token) |
|
|
| if not motion_groups_data: |
| |
| 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: |
| print(" Motion groups: Could not fetch") |
| 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] |
| if isinstance(controller, str): |
| controller_id = controller |
| else: |
| 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/update these in your .env.local file:") |
| print(f""" |
| NOVA_INSTANCE_URL={instance_url} |
| NOVA_ACCESS_TOKEN={access_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()) |
|
|