Twin & Dual-Device Connections
Connect two VOLTRA devices independently, pair them as Twin, and choose the correct status, control, and telemetry commands.
Two different two-device workflows
Cortex has two separate ways to work with two VOLTRA devices:
| Workflow | What it means | Data and control |
|---|---|---|
| Independent connections | Two physical devices are connected to the daemon as separate sessions. | Each device has its own status, commands, stream, and workout data. |
| Twin | Two already-connected devices are paired into one logical master/peer topology. | The master owns the logical Twin, Twin telemetry, and Twin History context. |
Connecting two devices does not automatically create a Twin. Complete the physical connections first, then run the Twin pairing command. When exactly two devices are connected, the command can choose roles from connection order: the first-connected device becomes the master.
Connect two devices independently
The current Cortex connection model supports up to two independent physical device sessions. Both devices must be nearby, powered on, and visible to the Bluetooth adapter.
voltra scan --all --json
voltra connect <DEVICE_A> --json
voltra connect <DEVICE_B> --jsonInspect the daemon and address each device explicitly:
voltra daemon status --json
voltra status --device-id <DEVICE_A> --json
voltra status --device-id <DEVICE_B> --jsonDevice-scoped control commands also accept --device-id:
voltra set-mode weight-training --device-id <DEVICE_A>
voltra set-weight 20 --device-id <DEVICE_A>
voltra set-mode weight-training --device-id <DEVICE_B>
voltra set-weight 20 --device-id <DEVICE_B>Without an explicit selector, a device command uses the daemon's active device.
Use --device-id when two devices are connected so a command cannot be sent to
the wrong session.
Disconnect one device without ending the other session:
voltra disconnect --device-id <DEVICE_A> --jsonThe third physical connection is rejected after two sessions are active. If a
second connection returns already connected ... Run: voltra disconnect, the
installed Cortex build predates independent dual-device sessions. Update to a
build that includes this capability, stop the background daemon, and retry:
voltra update
voltra daemon stop --jsonPair the sessions as Twin
Twin pairing requires both devices to be connected, compatible, and idle. You
can either let Cortex use connection order, or explicitly choose one device as
the master and the other as the slave. Do not start pairing while either
device is training.
Check the master's current topology before pairing:
voltra twin status --master <MASTER> --jsonPair the two sessions:
voltra twin pair --jsonWith exactly two connected devices, the first-connected device becomes the master. To override that order, provide both selectors:
voltra twin pair --master <MASTER> --slave <SLAVE> --jsonvoltra twin connect is a strict alias for voltra twin pair and follows the
same connection-order selection:
voltra twin connect --jsonTo override the order with the alias, provide both selectors:
voltra twin connect --master <MASTER> --slave <SLAVE> --jsonThe pairing flow confirms the peer identity, establishes the Twin topology,
and persists the pair identity locally. Two successful voltra connect
commands are not enough to claim that a Twin exists; use voltra twin status
and report the explicit topology state.
Twin ownership and training boundaries
The master owns the logical Twin and its History context. Use the master in
Twin-specific commands. Once the Twin is confirmed, the connected master is
the default target for status, finish-training, unload, and the Twin
commands. Do not pass the slave ID to ordinary training commands. Use
--master only when several connected sessions or pairs make the target
ambiguous; it is an optional disambiguation selector.
The daemon-backed status JSON includes topology with the Twin kind, state,
role, masterDeviceId, and slaveDeviceId. A one-shot direct status can only
report the master-owned device and topology fields returned by the device's
EP_STATUS response. During a confirmed Twin, do not pass the slave selector:
the slave has no independent live session. For example:
voltra status --jsonConfirmed Twin training supports:
- Weight Training
- Resistance Band
- Damper
- Isokinetic
- Isometric
- Rowing
- Skiing
Custom Curve and Sled Pull are not supported in Twin mode. Do not retry those commands while paired; unpair first if the user needs a single-device mode.
If twin status reports a pairing or degraded state, do not treat the two
physical sessions as a healthy Twin. Resolve the reported topology state before
starting or resuming Twin training.
Twin telemetry
voltra stream is the unified telemetry command. It does not merge two
independent sessions: an independent device produces voltra.training.v7, and
a confirmed Twin automatically produces the logical
voltra.training.twin.v1 stream.
For a confirmed Twin, use it without a selector in the normal flow:
voltra stream --output ./twin.ndjsonIf multiple Twin pairs are connected, select the logical master with
voltra stream --device-id <MASTER>. Never select the slave. The command uses
the voltra.training.twin.v1 NDJSON contract; it is a telemetry command, not a
History upload command. Do not pass --json; it already writes one JSON event
per line.
If the pair becomes degraded or the peer cannot be revalidated, stop and report the daemon error instead of silently treating the stream as a single-device session.
Unpair and clean up
When the devices are already paired as a Twin, control the master only. The slave rejects direct control commands. The normal cleanup is:
voltra finish-training --json
voltra twin unpair --jsonDo not run finish-training against <SLAVE>. twin unpair refreshes both
sessions and checks that both devices report trainingMode=none and
powerEnabled=false. If it reports that a device is still in a workout or
loaded, unload the master and retry the two-command cleanup:
voltra unload --json
voltra finish-training --json
voltra twin unpair --jsonIf more than one Twin pair is connected, add --master <MASTER> to the Twin
commands to select the intended pair. Do not use the slave ID as a selector.
After unpairing, the devices return to independent physical sessions. They can be inspected or disconnected separately:
voltra status --device-id <MASTER> --json
voltra status --device-id <SLAVE> --json
voltra disconnect --device-id <MASTER> --json
voltra disconnect --device-id <SLAVE> --json