# Multi-Device Setup

A single DepthAI `Pipeline` can run nodes on multiple OAK devices. Add devices to the pipeline, assign each device node to its
target device, and link outputs to inputs as usual. Links across devices are automatically relayed through the host.

See [Multi-Device Pipelines](https://docs.luxonis.com/software-v3/depthai/depthai-components/multi-device.md) for the API,
synchronization options, device loss handling and the common coordinate system.

## Discovering OAK cameras

You can use DepthAI to discover all connected OAK cameras, either via USB or through the LAN (OAK POE cameras). The code snippet
below finds all OAK cameras and prints their `DeviceIDs` (unique identifier) and their `XLink state`.

```python
import depthai
for device in depthai.Device.getAllAvailableDevices():
    print(f"{device.getDeviceId()} {device.state}")
```

Example results for 3x DepthAI on a system:

```bash
14442C10D13EABCE00 XLinkDeviceState.X_LINK_UNBOOTED
14442C1071659ACD00 XLinkDeviceState.X_LINK_UNBOOTED
3604808376 XLinkDeviceState.X_LINK_GATE
```

## Selecting a Specific DepthAI device to be used

From the Detected devices(s) above, use the following code to select the device you would like to use with your pipeline. For
example, if the first device is desirable from above use the following code:

```python
# Specify DeviceID, IP Address or USB path
device_info = depthai.DeviceInfo("14442C108144F1D000") # DeviceID
#device_info = depthai.DeviceInfo("192.168.1.44") # IP Address
#device_info = depthai.DeviceInfo("3.3.3") # USB port name
with depthai.Device(device_info) as device:
    ...
```

And you can use this code as a basis for your own use cases, such that you can run differing neural models on different OAK
models.

## Specifying POE device to be used

You can specify the POE device to be used by the IP address as well, as shown in the code snippet above.

Now use as many OAK cameras as you need! And since DepthAI does all the heavy lifting, you can usually use quite a few of them
with very little burden to the host.

## Timestamp syncing

Timestamp synchronization, alternatively referred to as message syncing, involves aligning messages from various sensors,
including frames, IMU packets, ToF data, and more.

Run a [Sync](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/sync.md) node on the host with
`sync.setRunOnHost(True)` and link camera outputs from multiple devices into its inputs. This groups frames by timestamp; it does
not itself synchronize camera exposures.

The [multi-device frame sync
example](https://github.com/luxonis/depthai-core/blob/main/examples/python/MultiDevice/multi_device_frame_sync.py) supports RVC4
cameras with host timestamp grouping, external FSYNC (`--external-sync`), or PTP (`--ptp-sync`). Hardware sync requires the
corresponding wiring or network configuration.

More information about timestamp synchronization can be found on the [time based synchronization
page](https://docs.luxonis.com/hardware/platform/deploy/data-sync/time-based-sync.md).

## One pipeline for multiple devices

Use `dai.Pipeline(False)` to start without automatically opening a default device. `pipeline.addDevice(device_info)` opens and
registers each selected device; the first device added becomes the default. Pass the device explicitly when creating a node to
select where it runs.

```python
import cv2
import depthai as dai

infos = dai.Device.getAllAvailableDevices()
if not infos:
    raise RuntimeError("No OAK devices found")

with dai.Pipeline(False) as pipeline:
    queues = {}
    for info in infos:
        device = pipeline.addDevice(info)
        camera = pipeline.create(dai.node.Camera, device).build(
            dai.CameraBoardSocket.CAM_A
        )
        queues[device.getDeviceId()] = camera.requestOutput(
            (640, 400), dai.ImgFrame.Type.BGR888p
        ).createOutputQueue(maxSize=2, blocking=False)

    pipeline.setDeviceStateCallback(
        lambda device, state: print(f"{device.getDeviceId()}: {state}")
    )
    pipeline.start()

    while pipeline.isRunning():
        for device_id, queue in queues.items():
            frame = queue.tryGet()
            if frame is not None:
                cv2.imshow(device_id, frame.getCvFrame())
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

cv2.destroyAllWindows()
```

### Links between devices

Outputs can link directly to inputs on another device. For example, a Camera on device A can feed an ImageManip on device B.
DepthAI inserts the host relay automatically, so no manual queue forwarding is required. These links use the host and both
devices' connections; account for their bandwidth when choosing frame sizes and rates.

See the [device-to-device relay
example](https://github.com/luxonis/depthai-core/blob/main/examples/python/MultiDevice/device_to_device_relay.py).

### Disconnection and reconnection

When a device disconnects, its streams go idle while DepthAI attempts to reconnect it. Other devices continue running. Poll queues
with `tryGet()` when displaying independent streams so an idle device does not block processing of the others.

Use `pipeline.setDeviceStateCallback(callback)` to receive device state transitions. The callback receives the device and its
state and runs on that device's monitor thread. Keep it short, and do not call pipeline start or stop directly from it.

By default, after reconnection attempts are exhausted, independent devices can continue running. The pipeline stops if the last
active device fails or a failed device consumes streams from other devices. Use `pipeline.setStopOnDeviceLoss(True)` to stop when
any participating device fails permanently.

## Multi camera calibration

DepthAI v3.11.0 adds the
[MultiDeviceCalibration](https://docs.luxonis.com/software-v3/depthai/depthai-components/host_nodes/multi_device_calibration.md)
node, which estimates the pose between several devices inside the pipeline and returns a calibration graph the pipeline can apply.
The example below is the older host-side approach.

This example demonstrates how to compute extrinsic parameters (pose of the camera) for multiple cameras. It provides a practical
illustration of how to determine the relative positions and orientations of different cameras in a multi-camera setup. By
accurately estimating the extrinsic parameters, we can ensure that the images captured by each camera are correctly aligned and
can be effectively combined for further processing and analysis.

### Multiple camera calibration on GitHub

[Multiple camera calibration on
GitHub](https://github.com/luxonis/oak-examples/tree/main/tutorials/multiple-devices/multi-cam-calibration)
