> ## 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:

> [tab] 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] 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);
> ```

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.

> [!NOTE]
>
> **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](https://docs.wuji.tech/docs/en/wuji-hand/latest/sdk-reference/device-operations.md) 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](https://docs.wuji.tech/docs/en/wuji-glove/latest/getting-started.md#step-network) for setup steps
> * **Wuji Hand**: connects over USB, no network setup required

When running the SDK on macOS, allow the terminal or IDE to access the device’s local network if prompted for local network permission. If the system firewall is enabled and prompts you to allow incoming connections for the application, select Allow.

On macOS 15 or later, if you denied local network access, enable it for the terminal or IDE in **System Settings › Privacy & Security › Local Network**.

## Connecting to a Device

> [!NOTE]
>
> `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 `.`.

### 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:

> [tab] Python
>
> ```python theme={null}
> glove = manager.connect(sn="WG1JA00XXXXXXXXX", device_name="glove")
> ```

> [tab] 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;
> }
> ```

### Connect by Address

Manually connect using IP address and port:

> [tab] Python
>
> ```python theme={null}
> glove = manager.connect(address="192.168.1.100:50000", device_name="glove")
> ```

> [tab] 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);
> ```

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:

> [tab] 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] 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);
> ```

`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.

On a Mac with Apple silicon, Wuji Hand and its tactile glove need no extra USB driver. Unplugging the Wuji Hand USB cable reports `USB I/O error: device disconnected`. After plugging it back in, reconnect the device and recreate subscriptions.

### 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).

> [!NOTE]
>
> 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.

### Connection Options

Configure timeout, retries, and device sharing:

> [tab] 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] 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);
> ```

`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`:

> [tab] 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] 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));
> ```

> [!NOTE]
>
> 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.

## Disconnecting

> [tab] 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] C
>
> ```c theme={null}
> // Disconnect first, then release the handle — both calls are required
> wuji_dev_disconnect(glove);
> wuji_dev_release(glove);
> ```

> [!NOTE]
>
> When a device is disconnected, all subscriptions on that device are automatically closed. You'll need to re-establish subscriptions after reconnecting.

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](https://docs.wuji.tech/docs/en/wuji-sdk/latest/data-reference.md).


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