Metadata-Version: 2.4
Name: orion-bridge
Version: 3.8.1
Summary: ORION Lab Bridge — Modular device bridge for industrial robotics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: websockets>=12.0
Requires-Dist: rich>=13.0
Requires-Dist: tomli-w>=1.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Requires-Dist: python-dotenv>=1.0
Requires-Dist: customtkinter>=5.2
Requires-Dist: supabase>=2.4.0
Requires-Dist: pyjwt[crypto]>=2.8.0
Requires-Dist: xarm-python-sdk
Provides-Extra: cloud
Requires-Dist: supabase>=2.4.0; extra == "cloud"
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == "cloud"
Provides-Extra: gui
Requires-Dist: customtkinter>=5.2; extra == "gui"
Provides-Extra: xarm
Requires-Dist: xarm-python-sdk; extra == "xarm"
Provides-Extra: abb
Provides-Extra: plc
Requires-Dist: python-snap7; extra == "plc"
Provides-Extra: gazebo
Requires-Dist: roslibpy; extra == "gazebo"
Provides-Extra: mujoco
Requires-Dist: mujoco>=3.5.0; extra == "mujoco"
Requires-Dist: numpy>=1.24; extra == "mujoco"
Provides-Extra: sim-viewer
Requires-Dist: mujoco>=3.5.0; extra == "sim-viewer"
Requires-Dist: numpy>=1.24; extra == "sim-viewer"
Requires-Dist: imgui-bundle>=1.3; extra == "sim-viewer"
Requires-Dist: PyOpenGL>=3.1; extra == "sim-viewer"
Requires-Dist: glfw>=2.5; extra == "sim-viewer"
Provides-Extra: http
Requires-Dist: flask; extra == "http"
Provides-Extra: all
Requires-Dist: supabase>=2.4.0; extra == "all"
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == "all"
Requires-Dist: customtkinter>=5.2; extra == "all"
Requires-Dist: xarm-python-sdk; extra == "all"
Requires-Dist: python-snap7; extra == "all"
Requires-Dist: roslibpy; extra == "all"
Requires-Dist: mujoco>=3.5.0; extra == "all"
Requires-Dist: numpy>=1.24; extra == "all"
Requires-Dist: flask; extra == "all"

# ORION Lab Bridge

Modular WebSocket bridge for industrial robotics labs.
Connects physical and simulated devices (xArm, ABB, Siemens PLC, shell)
to the ORION platform.

## Quick start

### Option A — one line, no Python required

This installs [uv](https://docs.astral.sh/uv/), downloads Python 3.10 if
needed, and puts the `orion` command on your PATH. Nothing to preinstall.

**Windows (PowerShell):**

```powershell
irm https://raw.githubusercontent.com/Starman26/orion-bridge-v2/main/install.ps1 | iex
```

**Linux / macOS:**

```bash
curl -LsSf https://raw.githubusercontent.com/Starman26/orion-bridge-v2/main/install.sh | sh
```

Then:

```bash
orion login   # authenticate (first time)
orion         # opens the GUI (use `orion --cli` for the terminal menu)
```

To include optional hardware drivers (`mujoco`, `plc`, `abb`, `gazebo`,
`http`), set `ORION_EXTRAS` before running the one-liner, e.g.
`$env:ORION_EXTRAS = "mujoco,plc"` (PowerShell) or `ORION_EXTRAS="mujoco,plc"`
(bash).

### Option B — already have Python? Just pip install

```bash
pip install --upgrade "orion-bridge[all]"   # core + GUI + all device drivers
orion                                        # opens the GUI (use `orion --cli` for the terminal menu)
```

The GUI ships with the core package, so even a plain `pip install
orion-bridge` gives a working `orion --gui`. On Windows the first run
registers the Python Scripts directory in your user PATH automatically —
if `orion` is not recognized right after installing, open a new terminal.
If another program named `orion` shadows the command (e.g. Oracle's ORION
disk benchmark), use the `orion-bridge` alias or `python -m orion_bridge`.

For a lighter install pick only the device drivers you need:

```bash
pip install "orion-bridge[xarm]"    # physical xArm only
pip install "orion-bridge[mujoco]"  # MuJoCo simulation
pip install "orion-bridge[gazebo]"  # Gazebo via rosbridge
pip install "orion-bridge[plc]"     # Siemens S7 snap7
pip install "orion-bridge[http]"    # PLC REST sidecar (Flask)
```

Available extras: `xarm`, `abb`, `plc`, `gazebo`, `mujoco`, `http`, `all`

## Configuration

Profiles are stored in `~/.orion/connections.toml`.
The wizard creates this file on first run. You can also edit it directly.

### connections.toml format

```toml
# Which profile to use when no --connection flag is given
[default]
profile = "mezzanine"

# One [connections.<name>] section per lab
[connections.mezzanine]
server    = "wss://your-server.example.com/ws/robot"
lab_id    = "mezzanine"
bridge_id = "hostname-mezzanine"   # unique per bridge process
token_env = "ORION_TOKEN_MEZZANINE"  # real token read from this env-var

[[connections.mezzanine.devices]]
type = "xarm"
id   = "xarm-lab1"
ip   = "192.168.1.185"

[[connections.mezzanine.devices]]
type = "shell"
id   = "shell-local"

# A second profile (e.g. local dev)
[connections.dev]
server    = "ws://localhost:8000/ws/robot"
lab_id    = "dev"
bridge_id = "localhost-dev"
token_env = "ORION_TOKEN_DEV"

[[connections.dev.devices]]
type    = "xarm"
id      = "xarm6-mujoco"
handler = "mujoco"
viewer  = true
mjcf_path = "sim/models/xarm6/scene_xarm6.xml"
```

### Token management

The token is **never stored in the TOML file**. Set the env-var named in
`token_env` before starting:

```bash
export ORION_TOKEN_MEZZANINE="your-secret-token"
orion --connection mezzanine
```

Or use a `.env` file with `python-dotenv` / `direnv`.

### CLI flags

| Flag | Description |
|------|-------------|
| `orion` | Interactive wizard (first run) or menu |
| `orion --list` | Print all saved profiles |
| `orion --connection NAME` | Start bridge using a specific profile |
| `orion --local` | Run without a server (local dispatch only) |
| `orion --config FILE` | Legacy: load a JSON config file |

### Migrating from lab_config.json

If you have a legacy `lab_config.json` from an older installation, run `orion`
once — the bridge automatically detects the file and migrates it to
`connections.toml`. The JSON file is left untouched.

You can also migrate manually from Python:

```python
from orion_bridge.connections import migrate_from_json
name = migrate_from_json("lab_config.json")
print(f"Migrated to profile '{name}'")
```

## Supported devices

| Type | Handler | Notes |
|------|---------|-------|
| `xarm` | `physical` (default) | UFACTORY SDK over IP |
| `xarm` | `mujoco` | MuJoCo simulation (`pip install mujoco`) |
| `xarm` | `gazebo` | Gazebo via rosbridge (`pip install roslibpy`) |
| `abb`  | TCP socket | RAPID SocketServer |
| `plc`  | snap7 | Siemens S7-1200 (`pip install python-snap7`) |
| `shell` | subprocess | Local commands (whitelisted) |

## Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `ORION_BRIDGE_ID` | Yes | Unique bridge ID, provisioned by owner |
| `ORION_BRIDGE_TOKEN` | Yes | Unique bridge token, provisioned by owner |
| `SUPABASE_URL` | Yes | Supabase project URL |
| `SUPABASE_ANON_KEY` | Yes (for `orion login`) | Anon key — NOT service_role |

## Authentication

Bridges have two authentication layers:

1. **Bridge identity**: `ORION_BRIDGE_ID` + `ORION_BRIDGE_TOKEN`, provisioned
   once and stored in `.env`. Required for the bridge to connect to the server.
2. **User identity**: `orion login` with email OTP. Required for `orion repl`.

```bash
orion login     # sends OTP to your email, stores JWT in ~/.orion/credentials.json
orion logout    # removes stored credentials
orion repl      # interactive REPL — requires prior login
```

`orion` (menu) and `orion --start` work without login.

## Development

```bash
pip install -e ".[all]"   # editable install with all extras
pytest tests/ -v
```
