# Monitor Multiple Devices on One Dashboard

> How to read several devices at once without juggling terminal windows. Serial Studio's multi-device mode gives each source its own protocol and parser.
>
> Data Sources · July 8, 2026 · by Alex Spataru · https://serial-studio.com/blog/multiple-devices-one-dashboard

Sooner or later a project outgrows one cable. A flight computer and a ground sensor. A device under test and the instrument measuring it. Two nodes of the same robot. The moment two devices matter to the same experiment, you hit a limitation that almost every serial tool shares: it opens one port at a time.

The usual answer is to open the tool twice. Two windows, two logs, and you as the correlation engine, glancing between them trying to decide whether the voltage dip in one window happened before or after the reset in the other. It works right up until the moment you actually need it to, which is when something goes wrong across both devices at once.

The short answer is to merge the streams at the host: Serial Studio's multi-device mode gives each device its own connection, protocol and parser, all feeding a single dashboard. The rest of this post explains why that is the right place to merge, and how the mode works.

## Where to merge the streams

There are really only two places to bring multiple devices together, and the trade-off between them is worth understanding before you pick a tool.

**Merge at the source.** One device becomes the aggregator: the second board sends its readings to the first over I2C, UART or radio, and the first forwards a combined stream to the computer. This is how many flight computers already work, and it is the right design when the aggregation itself is part of the product. But for bench work it is a lot of ceremony. You are writing forwarding firmware, inventing a combined packet format, and debugging a link between the devices before you have debugged the devices themselves. And if the aggregator resets, everything goes dark.

**Merge at the host.** Each device keeps its own connection and its own protocol, and the computer receives them side by side. Nothing changes in firmware. Both streams land on the same clock, so one recording captures the true ordering of events, and a failure in one device is just a gap in one lane instead of a blackout.

Host-side merging is the cleaner answer for test and integration work. It just requires the software on the host to actually support it.

## How multi-device mode works

Serial Studio handles this with a concept called sources. A [project file](https://serial-studio.com/help/project-editor) normally defines one device; in multi-device mode it defines several, and each source carries its own complete I/O configuration:

- its own bus type, so one source can be a serial port while another is a TCP socket, a Bluetooth LE characteristic or an [MQTT topic](https://serial-studio.com/blog/what-is-mqtt);
- its own connection settings, framing and checksum, because two devices rarely speak the same dialect;
- optionally its own [frame parser](https://serial-studio.com/blog/frame-parsers-and-the-empty-parser) in JavaScript or Lua, so a binary protocol on one device can live next to plain CSV on another.

You add sources in the Project Editor, which names them Device A, Device B and so on until you rename them. Groups and widgets belong to a source, so each device's data flows to its own plots and gauges. When you press **Connect**, every configured device connects at once.

Each source is parsed independently, with its own frame reader and its own isolated script engine. That isolation is the point: a device that floods the link with garbage cannot stall or corrupt the parsing of its neighbor. The [data flow reference](https://serial-studio.com/help/data-flow) walks through the pipeline in detail.

## One timeline for everything downstream

Merging at the host pays off downstream of the parser too. CSV and MDF4 recordings capture all sources into one file and play back the same way, so a post-flight review sees both devices on a shared timeline instead of two logs you align by hand. The console keeps per-device streams, and [output widgets](https://serial-studio.com/blog/control-devices-scpi-gcode) target a specific device, so a dashboard can send a command to one board without the other ever seeing it.

## Two crystals never agree

There is a physics problem hiding under the words "shared timeline", and it is worth staring at before you trust any long recording: the two devices do not share a clock. Each board runs from its own oscillator, and oscillators disagree. An ordinary crystal is specified to a few tens of parts per million; a microcontroller's internal RC oscillator is off by a percent or more and wanders with temperature. Parts per million sound negligible until you multiply by a long run. Two boards on ±50 ppm crystals can disagree by 100 microseconds after one second, six milliseconds after a minute, and over four *seconds* across a 12-hour soak test. On internal RC oscillators the divergence is measured in minutes. If each device stamps its own samples and you take those stamps at face value, the merged timeline shears apart so slowly that nothing ever looks wrong; two events that were simultaneous at hour zero appear seconds apart at hour twelve.

Host-side merging is the first defense, because it gives everything one clock: every frame from every source is stamped on arrival by the same computer. That makes cross-device ordering trustworthy to within transport jitter, which for USB serial adapters means [buffering on the order of milliseconds to tens of milliseconds](https://serial-studio.com/blog/how-to-read-a-serial-port). For "did the voltage dip before the reset", that is plenty.

When you need better than arrival time, the discipline is to treat device time as data and measure the disagreement instead of assuming it away. Have each device send a sample counter or millisecond timestamp in its frames, the same habit [production firmware uses to answer "when"](https://serial-studio.com/blog/telemetry-lessons-from-production-firmware). On the host, a [dataset transform](https://serial-studio.com/blog/sensor-data-transforms) sees both clocks at once: the device's counter arrives as the value, and `info.timestampMs` supplies the host's monotonic clock. Anchor them together on the first frame and the difference becomes a measurable skew:

```lua
local anchor
function transform(value)
  local device_ms = value * 10   -- counter incremented at 100 Hz
  if anchor == nil then
    anchor = info.timestampMs - device_ms
  end
  tableSet("clocks", "dev_a_skew", info.timestampMs - device_ms - anchor)
  return value
end
```

Give each source its own copy and plot the skew registers as virtual datasets. A healthy pair of crystals draws two nearly straight, slowly separating lines whose slope *is* the relative drift rate, and the recording now carries the correction factor for aligning the data afterward. A step in the line, rather than a slope, means something else entirely: a dropped batch of frames or a device reset, caught because the clock disagreement was on the dashboard instead of hidden in the assumptions.

The honest ceiling: host software can measure drift, but it cannot see below the transport's own jitter. Correlating two devices to better than a millisecond needs hardware, a shared trigger line, GPS pulse-per-second, or PTP, exactly the ladder that applies within a single device. For everything above that threshold, one host clock plus per-device counters covers the bench.

## Watch it run, no hardware required

Everything above is easier to believe when you can watch it happen. One of the shipped examples does exactly that: two simulated devices, two different protocols, one live dashboard.

The bundled [Dual Drone Telemetry example](https://serial-studio.com/examples#Dual%20Drone%20Telemetry) is the clearest demonstration, and it needs nothing but Python. A simulator flies two drones over the Swiss Alps near Zermatt and serves each one on its own TCP port, 9001 and 9002. The two streams are genuinely different: each drone uses its own hexadecimal frame delimiters, interleaves JPEG camera frames with CSV telemetry in the same byte stream, and renders a different camera style, satellite imagery for one and a thermal palette for the other.

The dashboard shows both drones side by side: maps, attitude indicators, battery gauges and camera feeds, with a control panel per drone. The project launches the simulator automatically when you connect, so opening the `.ssproj` file and pressing **Connect** is the whole setup. The camera imagery needs the optional `opencv-python` and `numpy` packages; everything else works without them.

The most instructive control is the one labeled **Crash**. It drops one drone's TCP connection mid-flight, with the other still streaming. That is exactly the failure that two-terminal-windows workflows handle worst, and here it is just one set of widgets going quiet while the rest of the dashboard carries on.

## Multi-device setup and licensing notes

The free GPL edition connects to one source at a time; defining multiple sources in a project needs a [Pro license](https://serial-studio.com/help/pro-vs-free). While a multi-device project is active, the driver buttons in the toolbar are disabled and the Setup panel shows a notice instead of connection settings, because each source's configuration lives in the Project Editor rather than in a single global panel.

The [Data Sources reference](https://serial-studio.com/help/data-sources) documents multi-device mode alongside all ten drivers. If you are still deciding whether your data even needs a serial port, [Serial Studio Isn't Just for Serial Ports](https://serial-studio.com/blog/not-just-serial-ports) covers what those drivers can read.
