> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wuji.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Device Discovery & Connection

Connecting takes three steps: scan the local network and local USB bus for a device list, locate the target by serial number, address, or handedness, and let the SDK hold the connection until you close it explicitly. Python and C share the same semantics. They differ in error reporting and handle lifetime.

## Device Discovery

Scan for Wuji devices connected via Ethernet on the local network or over USB:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from wuji_sdk import SdkManager

    manager = SdkManager.instance()
    devices = manager.scan()

    for dev in devices:
        print(f"SN: {dev.sn}, Type: {dev.device_type}, Address: {dev.address}")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    #include "wuji_sdk.h"

    wuji_init(NULL);

    WujiDiscovered *devs = NULL;
    size_t count = 0;
    wuji_scan(&devs, &count);

    for (size_t i = 0; i < count; i++) {
        printf("SN: %s, Type: %s, Address: %s\n",
               devs[i].serial_number, devs[i].model, devs[i].address);
    }
    wuji_discovered_free(devs, count);
    ```
  </Tab>
</Tabs>

Each discovered record carries the serial number, address, and device type, so you can tell what a device is before connecting. In Python, `DiscoveredDevice.device_type` is a `DeviceType` enum (`WujiGlove` / `WujiHand2` / `WujiHand`). In C, `WujiDiscovered.device_id` is a `WujiDeviceType` enum (`WUJI_DEVICE_TYPE_WUJI_GLOVE` / `_WUJI_HAND_2` / `_WUJI_HAND`). `Unknown` and `WUJI_DEVICE_TYPE_UNKNOWN` mean the type was not available at scan time or isn't recognized by this SDK build.

<Info>
  **Network prerequisite**: Ethernet devices use static IPs, not DHCP. Before scanning or connecting, set your host NIC to the same subnet (for example `192.168.1.50`, avoiding the device default addresses), or the devices can't be discovered or reached.

  * **Wuji Hand 2**: left hand `192.168.1.110`, right hand `192.168.1.111` — see [Wuji Hand 2 SDK Reference — Device Operations](/en/docs/wuji-hand/latest/sdk-reference/device-operations/) for address details and how to change the IP
  * **Wuji Glove**: left hand `192.168.1.100`, right hand `192.168.1.101` — see [Wuji Glove Getting Started](/en/docs/wuji-glove/getting-started/#step-network) for setup steps
  * **Wuji Hand**: connects over USB, no network setup required
</Info>

## Connecting to a Device

<Info>
  `device_name` in all connect APIs is a **local alias**, used only to look up the device later and to namespace resource paths. It does not select a device and does not determine the returned handle type. The returned type is determined by the actual connected device. The name must be non-empty and must not contain `/` or `.`.
</Info>

### Choose a Connection Method

Pick by how many devices are currently discovered. See [Auto Connect](#auto-connect), [Connect by SN](#connect-by-sn), [Connect by Address](#connect-by-address), [Connect by USB](#connect-by-usb), and [Connect by Handedness](#connect-by-handedness):

```text theme={null}
How many devices does scan() currently find?
│
├─ exactly one ──▶ auto_connect() — works for USB and Ethernet alike
│
└─ multiple ▶ connect() with an explicit locator — sn / address / handedness are mutually exclusive
     ├─ sn=... — any device, most precise (filter USB devices by TransportType.Usb first)
     ├─ address=... — direct connect when you know the IP
     └─ handedness=... — by hand side (Wuji Hand 2 / Wuji Glove)
          └─ multiple same-side devices ▶ AmbiguousHandedness ▶ use sn
```

Any method can take [Connection Options](#connection-options) to configure timeout, retries, and device sharing.

### Auto Connect

`auto_connect()` connects to the single device currently discovered. If multiple devices are present, the call fails because the target is ambiguous. Use `connect()` to disambiguate in that case:

```python theme={null}
glove = manager.auto_connect(device_name="glove")
print(f"Connected: {glove.serial_number}")
```

C has no equivalent. Call `wuji_scan()`, confirm the list holds exactly one record, then take its `serial_number` and follow [Connect by SN](#connect-by-sn).

### Connect by SN

Connect to a specific device by serial number:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    glove = manager.connect(sn="WG1JA00XXXXXXXXX", device_name="glove")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiConnectTarget target = {
        .kind = WUJI_CONNECT_TARGET_KIND_SN,
        .value = "WG1JA00XXXXXXXXX",
    };

    WujiDevice *glove = NULL;
    if (wuji_connect(&target, "glove", NULL, &glove) != WUJI_STATUS_OK) {
        fprintf(stderr, "connect failed: %s\n", wuji_last_error());
        return 1;
    }
    ```
  </Tab>
</Tabs>

### Connect by Address

Manually connect using IP address and port:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    glove = manager.connect(address="192.168.1.100:50000", device_name="glove")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiConnectTarget target = {
        .kind = WUJI_CONNECT_TARGET_KIND_ADDR,
        .value = "192.168.1.100:50000",
    };

    WujiDevice *glove = NULL;
    wuji_connect(&target, "glove", NULL, &glove);
    ```
  </Tab>
</Tabs>

Include the port in the address. Use `IP:port` for IPv4. IPv6 addresses aren't supported. A bare IP address returns a missing-port error instead of being treated as a USB path. Serial port paths aren't supported either — scan first, then connect by SN.

### Connect by USB

Wuji Hand attaches over USB. Filter the scan results by transport type, then connect by serial number:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from wuji_sdk import SdkManager, TransportType

    manager = SdkManager.instance()
    usb_devices = [d for d in manager.scan() if d.transport_type == TransportType.Usb]

    hand = manager.connect(sn=usb_devices[0].sn, device_name="wuji_hand")
    print(f"Connected: {hand.serial_number} ({hand.handedness_name()})")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiDiscovered *devs = NULL;
    size_t count = 0;
    wuji_scan(&devs, &count);

    WujiDevice *hand = NULL;
    for (size_t i = 0; i < count; i++) {
        if (devs[i].transport == WUJI_TRANSPORT_TYPE_USB) {
            if (wuji_hand_connect_sn(devs[i].serial_number, "wuji_hand", &hand) != WUJI_STATUS_OK) {
                fprintf(stderr, "connect failed: %s\n", wuji_last_error());
                hand = NULL;
            }
            break;
        }
    }
    wuji_discovered_free(devs, count);
    ```
  </Tab>
</Tabs>

`wuji_hand_connect_sn()` is shorthand for `wuji_connect()` with SN targeting. Both return the same kind of device handle.

If a matching-handedness tactile glove is plugged in alongside the hand, the SDK auto-pairs it on connect. Check with `hand.is_tactile_attached()` in Python or `wuji_hand_is_tactile_attached()` in C. The value reflects the current attachment and turns false after the glove is unplugged at runtime. Once unplugged, the tactile status stream's `state` becomes 0 (not present), other tactile reads and subscriptions fail with a `tactile_not_present` error, and the hand itself keeps working. Re-attaching the glove requires reconnecting the hand.

### Connect by Handedness

Connect to a two-handed device (such as Wuji Hand 2 or Wuji Glove) by left or right hand, without looking up a serial number first. The SDK scans the local network and selects the unique device by the fourth character of its serial number (`J` for left, `K` for right):

```python theme={null}
from wuji_sdk import Handedness

# Connect the right-hand device
hand = manager.connect(handedness=Handedness.Right, device_name="wuji_hand_2")

# Connect the left-hand glove
glove = manager.connect(handedness=Handedness.Left, device_name="wuji_glove")
```

`handedness` is mutually exclusive with `sn` and `address`—specify only one.

C has no equivalent. In the `wuji_scan()` results, match `serial_number[3]` against `'J'` or `'K'` to isolate the target, then follow [Connect by SN](#connect-by-sn).

<Info>
  In Python, if no device matches the handedness, `DeviceNotFound` is raised. If multiple devices share the handedness, `AmbiguousHandedness` is raised with all candidate serial numbers. Specify `sn` explicitly instead.
</Info>

### Connection Options

Configure timeout, retries, and device sharing:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from wuji_sdk import ConnectOptions

    options = ConnectOptions(
        timeout_ms=1000,   # Connection timeout (milliseconds)
        retry_count=3      # Number of retries
    )

    glove = manager.connect(
        sn="WG1JA00XXXXXXXXX",
        device_name="glove",
        options=options
    )
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiConnectOptions options = wuji_connect_options_default();
    options.timeout_ms = 1000;   // Connection timeout (milliseconds)
    options.retry_count = 3;     // Number of retries

    WujiConnectTarget target = {
        .kind = WUJI_CONNECT_TARGET_KIND_SN,
        .value = "WG1JA00XXXXXXXXX",
    };

    WujiDevice *glove = NULL;
    wuji_connect(&target, "glove", &options, &glove);
    ```
  </Tab>
</Tabs>

`enable_bridge` (on by default) controls whether multiple SDK instances (including processes on other hosts) can connect to the same device. When enabled, this process shares the connected device. Turn it off for exclusive access — other instances can't reach the device through this process.

In C, always start from `wuji_connect_options_default()` and override only the fields you need. Zero-initializing the whole struct also clears `enable_bridge` and background time sync, which changes connection behavior. Pass `NULL` to `wuji_connect()` when the defaults are fine.

## Multi-device Management

The SDK supports connecting multiple devices simultaneously, each identified by a unique `device_name`:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    left = manager.connect(handedness=Handedness.Left, device_name="left_hand")
    right = manager.connect(handedness=Handedness.Right, device_name="right_hand")

    # Get all connected devices
    all_devices = manager.get_connected_devices()
    for name, device in all_devices:
        print(f"{name}: {device.serial_number}")

    # Get a device by name
    left = manager.get_device(device_name="left_hand")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiConnectTarget left_target = {
        .kind = WUJI_CONNECT_TARGET_KIND_SN,
        .value = "WG1JA00XXXXXXXXX",
    };
    WujiConnectTarget right_target = {
        .kind = WUJI_CONNECT_TARGET_KIND_SN,
        .value = "WG1KA00XXXXXXXXX",
    };

    WujiDevice *left = NULL, *right = NULL;
    wuji_connect(&left_target, "left_hand", NULL, &left);
    wuji_connect(&right_target, "right_hand", NULL, &right);

    // C has no alias registry — keep the handles yourself
    char name[64];
    wuji_dev_device_name(left, name, sizeof(name));
    printf("%s: connected=%u\n", name, wuji_dev_is_connected(left));
    ```
  </Tab>
</Tabs>

<Info>
  Use different `device_name` values to keep the left and right hand in the same process. Reconnecting to an already-active device raises `SessionAlreadyExists` in Python and returns a failure status in C. Neither drops the existing connection — keep using the existing handle.
</Info>

## Disconnecting

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    # Disconnect a specific device
    manager.disconnect(device_name="glove")

    # Or disconnect via the device object
    glove.disconnect()

    # Disconnect all devices managed by this manager
    manager.disconnect_all()
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    // Disconnect first, then release the handle — both calls are required
    wuji_dev_disconnect(glove);
    wuji_dev_release(glove);
    ```
  </Tab>
</Tabs>

<Info>
  When a device is disconnected, all subscriptions on that device are automatically closed. You'll need to re-establish subscriptions after reconnecting.
</Info>

The SDK owns the connection, and dropping a device object or handle variable doesn't close it. In Python, deleting or replacing a device object leaves the connection active until you call `disconnect()` or `disconnect_all()`, or until the process exits, so long-running programs should disconnect explicitly in a `finally` block. In C, `wuji_dev_release()` only returns the handle, so call `wuji_dev_disconnect()` before releasing it. With an exclusive connection, leaving the connection open also prevents other clients from connecting to the device.

## Interface List

| Operation | Python | C |
| - | - | - |
| Initialize and shut down the SDK | `SdkManager.instance()` | `wuji_init()`, `wuji_shutdown()` |
| Scan for devices | `manager.scan()` | `wuji_scan()`, `wuji_discovered_free()` |
| Connect the only discovered device | `manager.auto_connect(device_name=...)` | No equivalent — scan first, then call `wuji_connect()` with the serial number |
| Connect by serial number | `manager.connect(sn=...)` | `wuji_connect()` with `target.kind` set to `WUJI_CONNECT_TARGET_KIND_SN` |
| Connect by address | `manager.connect(address=...)` | `wuji_connect()` with `target.kind` set to `WUJI_CONNECT_TARGET_KIND_ADDR` |
| Connect a Wuji Hand over USB | Filter by `TransportType.Usb`, then `manager.connect(sn=...)` | `wuji_hand_connect_sn()` |
| Connect by handedness | `manager.connect(handedness=...)` | No equivalent — filter scan results on the fourth serial-number character, then call `wuji_connect()` |
| Configure connection parameters | `ConnectOptions(...)` | `wuji_connect_options_default()`, then override `WujiConnectOptions` fields |
| Read serial number and alias | `device.serial_number`, `device.device_name` | `wuji_dev_serial_number()`, `wuji_dev_device_name()` |
| Check connection state | `device.is_connected` | `wuji_dev_is_connected()` |
| Look up a device by alias | `manager.get_device(device_name=...)`, `manager.get_connected_devices()` | No equivalent — keep the device handles yourself |
| Disconnect one device | `device.disconnect()`, `manager.disconnect(device_name=...)` | `wuji_dev_disconnect()`, `wuji_dev_release()` |
| Disconnect every device | `manager.disconnect_all()` | No equivalent — call `wuji_dev_disconnect()` on each handle |

Python reports failures as exceptions. C reports them as `WujiStatus` return codes, with the reason available from `wuji_last_error()`. For build flags, linking, memory ownership, and the full status code list, see the [C Interface Reference](/en/docs/wuji-sdk/data-reference/).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.