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

# Best Practices

## Error Handling

SDK operation failures raise `WujiException` or one of its subclasses, such as `NodeOfflineError`, so catch `WujiException` at the SDK boundary. Only argument-type or overflow errors that the Python interpreter raises before the SDK call keep their native exception types:

```python theme={null}
from wuji_sdk import SdkManager, WujiException

try:
    manager = SdkManager.instance()
    glove = manager.auto_connect(device_name="glove")
    sub = glove.tactile().subscribe()
    frame = sub.recv()
except WujiException as e:
    error_msg = str(e)
    if "DeviceNotFound" in error_msg:
        print("Device not found, check connection")
    elif "Disconnected" in error_msg:
        print("Device disconnected")
    elif "Connection timeout" in error_msg:
        print("Connection timed out, check network/IP settings")
    elif "Operation timeout" in error_msg:
        print("Operation timed out, device not responding, retrying...")
    else:
        print(f"Error: {error_msg}")
```

For the full list of error types, see [Appendix — Python Exception Types](/en/docs/wuji-sdk/appendix/#python-exception-types). For C return codes and device fault codes, see [Appendix — Error Code Index](/en/docs/wuji-sdk/appendix/#error-code-index).

## Reconnection Strategy

After disconnection, reconnect and resubscribe:

```python theme={null}
import time
from wuji_sdk import SdkManager, WujiException

manager = SdkManager.instance()

def connect_with_retry(sn, max_retries=5):
    for attempt in range(max_retries):
        try:
            return manager.connect(sn=sn, device_name="glove")
        except WujiException:
            wait = 2 ** attempt  # Exponential backoff
            print(f"Connection failed, retrying in {wait}s...")
            time.sleep(wait)
    raise RuntimeError("Max retries exceeded")
```

## Multi-device Coordination

Collect data from multiple devices simultaneously:

```python theme={null}
import asyncio
from wuji_sdk import SdkManager

async def collect_from_device(glove, name):
    sub = glove.tactile().subscribe()
    while True:
        frame = await sub.recv_async()
        print(f"[{name}] max={max(frame.data):.1f}")

async def main():
    manager = SdkManager.instance()
    devices = manager.scan()

    gloves = []
    for i, dev in enumerate(devices):
        glove = manager.connect(sn=dev.sn, device_name=f"glove_{i}")
        gloves.append((glove, f"glove_{i}"))

    tasks = [collect_from_device(g, n) for g, n in gloves]
    await asyncio.gather(*tasks)

asyncio.run(main())
```

### Cross-device Merged Data

In multi-device setups, use global resources to get aggregated data from all devices without manual merging:

```python theme={null}
manager = SdkManager.instance()
left = manager.connect(sn="WG1JA00XXXXXXXXX", device_name="left")
right = manager.connect(sn="WG1KA00XXXXXXXXX", device_name="right")

# Subscribe to global coordinate transforms — automatically merges left and right hand data
sub = manager.tf_static().subscribe()
transforms = await sub.recv_async()
for tf in transforms.transforms:
    print(f"{tf.parent_frame_id} → {tf.child_frame_id}")
```

## Log Control

Adjust SDK log level for debugging:

```python theme={null}
import wuji_sdk

wuji_sdk.set_log_level("debug")   # Show debug information
wuji_sdk.set_log_level("trace")   # Show all logs
wuji_sdk.set_log_level("info")    # Default level
wuji_sdk.set_log_level("warn")    # Warnings only
wuji_sdk.set_log_level("error")   # Errors only
wuji_sdk.set_log_level("off")     # Disable logging
```

## Device Logging

Device logging access varies by product. See the corresponding device documentation:

* [Wuji Hand 2 Python flash log export](/en/docs/wuji-sdk/troubleshooting/#flash-log-export)
* [Wuji Hand 2 C SDK flash log export](/en/docs/wuji-hand/latest/sdk-reference/diagnostics/#flash-log-export)
* [Wuji Glove device logs](/en/docs/wuji-glove/sdk-data-reference/device-operations#device-logs)

## Data Collection and Privacy

Wuji SDK uploads anonymous usage data by default to help improve the product. It doesn't collect personal or sensitive information. For more details, see the [Privacy Policy](https://wuji.tech/en/terms/privacy). On first use, the terminal shows the following privacy notice:

```text theme={null}
Privacy Notice
Wuji SDK collects anonymous usage data to improve the product.
No personal or sensitive information is collected.
Privacy Policy: https://wuji.tech/en/terms/privacy
If your environment has information security requirements, you can disable telemetry upload for the current process by setting:
WUJI_TELEMETRY_DISABLE=1 <your_command>
```

To stop data uploads, set `WUJI_TELEMETRY_DISABLE` to `1` or `true` before starting the application.

```bash theme={null}
# Executable
WUJI_TELEMETRY_DISABLE=1 ./<your_program>

# Python script
WUJI_TELEMETRY_DISABLE=1 python <your_script.py>
```

## Recording Best Practices

### Choose the Right Compression

* Use `"lz4"` for real-time capture (low latency). Use `"zstd"` for long-term storage (high compression ratio)
* For high-frequency channels (>500 Hz), prefer `"lz4"` to avoid compression becoming a bottleneck

### Episode Management

Split long capture sessions into multiple episodes for easier playback and analysis:

```python theme={null}
import asyncio
from wuji_sdk import TopicRecorder

recorder = TopicRecorder(compression="lz4")
recorder.record(glove.tactile().subscribe())

for i in range(5):
    handle = await recorder.start(f"./data/episode_{i:03d}.mcap")
    await asyncio.sleep(60)  # 60 seconds per episode
    await handle.stop()
```

### Monitor Data Quality

For long recording sessions, enable quality monitoring and handle alerts promptly:

```python theme={null}
import asyncio

handle = await recorder.start("./data/session.mcap")

async def watch_alerts():
    async for alert in handle.subscribe_alerts():
        print(f"Warning: {alert.message}")

asyncio.create_task(watch_alerts())
```

## Performance Optimization

### Reduce Unnecessary Subscriptions

Only subscribe to data streams you actually need to avoid wasting bandwidth and CPU:

```python theme={null}
# ✓ Subscribe only to needed data
sub_tactile = glove.tactile().subscribe()

# ✗ Don't subscribe to unused data
# sub_imu = glove.imu_palm().subscribe()
```

### Close Subscriptions Promptly

Close subscriptions when they're no longer needed:

```python theme={null}
sub = glove.tactile().subscribe_with_callback(callback=on_data)
# ... done collecting data
sub.close()  # Release resources
```


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