Skip to main content
Version: 2.2.0

orca-client

orca-client is a small program you run on the computer your instruments are wired to. It opens one outbound WebSocket to the Orca daemon, takes commands on it, drives the instrument through its driver, and sends the answer back on the same connection.

Every device in a topology connects to Orca through orca-client, in DEVICE_SIM and LIVE, including when orca-client runs on the same computer as the daemon. PURE_SIM needs no orca-client: every device runs against a simulator inside Orca. If you are running the quickstart in simulation, skip this page.

  Lab bench PC                                Daemon host
+-----------------------------+ +--------------------------+
| shaker (serial) | | Orca runtime |
| arm (TCP) | | scheduler |
| liquid handler (USB) | | |
| | | | GET /ws/devices |
| v | | ^ |
| orca-client ----------|--- wss --->|----------+ |
+-----------------------------+ outbound +--------------------------+

orca-client always dials out. The daemon never dials in, so the bench PC needs no inbound firewall rule.

Install​

orca-client is not on PyPI, so install it from a clone. Python 3.10 or newer.

git clone https://github.com/Cheshire-Labs/orca-client.git
cd orca-client
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux, macOS
pip install -e .

pip also installs cheshire-drivers, which holds the driver classes and the protocol orca-client and the daemon use to talk, from GitHub at the release this version of orca-client pins.

Configure​

orca-client reads one JSON file. It defaults to config.json in the working directory, and --config points it somewhere else.

{
"client_id": "lab-workstation-1",
"site": "boston",
"lab": "molbio",
"workcell": null,
"platform": {
"url": "wss://your-deployment.example.com/ws/devices",
"api_key": "${ORCA_CLIENT_API_KEY}",
"heartbeat_interval": 30.0
},
"devices": []
}
FieldWhat it is
client_idA label for this orca-client, written into its own logs.
site, labHow the daemon names the connection. It registers orca-client as <site>-<lab>-client.
workcellOptional extra label. null is fine.
platform.urlThe daemon's /ws/devices endpoint. Required.
platform.api_keySent as the X-API-Key header when orca-client connects. Required, and must not be empty.
platform.heartbeat_intervalSeconds between heartbeats. Defaults to 30.
platform.reconnect_backoffSeconds to wait before each redial, in order. The last value repeats. Each value must be above 0. Defaults to [1, 2, 4, 8, 16, 30]. See Reconnecting.
devicesThe list described in the next section.

platform.url and platform.api_key may contain ${VAR}, which is replaced from the environment when the file is read. Keep the key out of the file that way. If the variable is not set, orca-client stops and names it. No other field is expanded.

Four fields also have an environment fallback. orca-client uses the variable only when the config file does not set the field:

VariableFalls back for
ORCA_CLIENT_URLplatform.url
ORCA_CLIENT_API_KEYplatform.api_key
ORCA_CLIENT_HEARTBEAT_INTERVALplatform.heartbeat_interval
ORCA_CLIENT_RECONNECT_BACKOFFplatform.reconnect_backoff, as comma-separated seconds: 1,2,5

--env path/to/.env loads a .env file before the config is read. Without it orca-client uses the process environment.

Which URL​

The scheme is checked when orca-client loads its config. ws:// is accepted only for localhost, 127.0.0.1 and ::1. Any other host must be wss://, and orca-client refuses to start otherwise.

The framework daemon binds 127.0.0.1 and picks a free port at start, so on a single machine the URL is ws://127.0.0.1:<port>/ws/devices. Pin the port with orca start --port 8765, or read the one it chose from orca status.

Authenticating​

The daemon checks the X-API-Key header when orca-client connects. If the check fails, it refuses the connection before the socket opens, which reaches orca-client as HTTP 403. orca-client then stops and says the platform rejected the API key. It does not redial, because the same key will be refused again. The framework daemon ships an allow-all check, because a single node trusts its own machine, so any non-empty key works there. A hosted deployment installs a real check and the key must be the one it issued.

Declare your devices​

Each entry in devices is one instrument. The daemon matches it to the topology by name: an orca-client device named shaker_1 is the topology's Shaker("shaker_1").

"devices": [
{
"type": "shaker",
"name": "shaker_1",
"driver": {
"type": "plr",
"backend": "InhecoThermoShake",
"connection": { "type": "serial", "port": "COM3", "baudrate": 9600 }
}
},
{
"type": "transporter",
"name": "arm_1",
"driver": {
"type": "plr",
"backend": "PreciseFlex",
"connection": { "type": "tcp", "host": "192.168.1.100", "tcp_port": 10100 }
}
}
]

type is the device kind, one of shaker, centrifuge, sealer, transporter, translator, liquid_handler, plate_washer, reader, delidder, storage, waste, thermocycler.

driver.type is how the instrument is driven:

driver.typeDrives
plrA real instrument through a PyLabRobot backend, named in backend.
venusA Hamilton run by Venus methods. Its settings go in a venus block; see Hamilton Venus.
simA simulated instrument, for testing the connection with no hardware attached.
humanA person who moves the plates, for a transporter. In LIVE orca-client prompts in its terminal at each pick and place, so run it in a terminal you can type into.

connection takes type of serial, tcp or usb, with port and baudrate for serial and host and tcp_port for TCP.

When a name does not match​

If the topology has no device with that name, the daemon still accepts it. No workflow can use it, and the topology device you meant stays disconnected. orca-client shows no error.

Two places show the mistake:

  • The daemon log. When orca-client connects, ~/.orca/daemon.log gets a warning: device 'shaker_l' connected but is not declared in topology. This check needs a mounted topology. Mount the topology before you start orca-client, or restart orca-client after you mount it.
  • The next DEVICE_SIM or LIVE submission. It is refused with Devices not currently connected: ['shaker_1'], which lists every topology device that is not connected.

type does not have to match the topology's device kind. If it differs, the daemon logs a warning and accepts the device. What must match is the interfaces: the device must have every interface the topology expects. If one is missing, the daemon refuses the connection. See One instrument, one orca-client.

Two things you do not configure here. Teachpoints stay on the daemon: it resolves them and sends the coordinates with each move command, so orca-client holds no local copy. And orca-client builds both a real driver and a sim driver for every device, then the daemon picks between them per run mode, so you do not switch modes in this file.

Run it​

python -m orca_client --config config.json
FlagEffect
--config, -cConfig file path. Defaults to ./config.json.
--env, -eLoad this .env file before reading the config.
--verbose, -vDebug logging.
--versionPrint the version and exit.

orca-client connects, sends its device list, then waits. Devices are left uninitialized on purpose. The daemon calls initialize when it is ready, so it owns the timing.

Confirm the device connected​

orca-client logs Connected to the Orca gateway as soon as the socket opens. The daemon can still refuse the connection after that. Check on the daemon.

The daemon log​

The daemon writes its log to ~/.orca/daemon.log. Set ORCA_DAEMON_HOME to use a different directory. When the daemon accepts orca-client, it writes two lines like these (timestamps removed):

orca.gateway.registry.connection_tracker INFO Registered client boston-molbio-client with 2 devices (site=boston, lab=molbio, workcell=None)
orca.gateway.websocket.router INFO Client boston-molbio-client registered with 2 devices

boston-molbio-client is <site>-<lab>-client from your config. 2 is the number of entries in devices. If the daemon refuses the connection, it logs a warning with the reason instead. The reasons are listed under Advanced.

One device​

orca device capabilities shaker_1

If orca-client has connected shaker_1, the answer comes from orca-client: type is the type in your config, and the methods listed are the driver's.

If not, the answer describes the sim driver inside Orca, and type is a class name such as SimShakerDriver. So type tells you whether orca-client is connected.

All devices​

orca device registry list shows each device name with what the topology declares and what orca-client reported. A device can have one without the other.

  • client: orca-client is connected.
  • device: the driver's connection to the instrument is open. This can be false while client is true.
  • link: which driver answered.
  • modes: the run modes the device can be used in.

orca device list is shorter: name, kind, busy, initialized, mode and fault for each device in the topology.

Advanced​

Read this when a connection is refused, or when you are working out what happens to a run while orca-client is away.

Protocol version​

orca-client and the daemon both take their protocol from cheshire-drivers, currently version 1.3.0. orca-client sends its version when it connects, and the daemon checks it before anything else.

A mismatch is fatal and immediate. The daemon closes the socket with code 1002 and the reason Incompatible protocol version: expected <version>. There is no negotiation and no compatibility window, so orca-client and the daemon must come from matching builds. Upgrade one, upgrade the other.

Reconnecting​

A dropped connection is retried automatically. Before each redial orca-client waits the next value in platform.reconnect_backoff, and repeats the last value once it runs out. With the default that is 1, 2, 4, 8, 16, then 30 seconds between every later attempt. It keeps trying until you stop it.

The list starts again from the first value after any connection that opened, whether it closed cleanly or dropped. So a daemon restart is followed by a 1 second wait, however many restarts came before it.

orca-client stops instead of redialing when the daemon refuses it for a reason a retry cannot fix: a rejected API key (see Authenticating), a protocol version mismatch, a device claimed by another orca-client, or a driver the topology contradicts (see One instrument, one orca-client). The last three close the socket with code 1002, and orca-client stops on every 1002 close. The close reason names what to fix.

On reconnect the daemon assumes nothing survived. A returning orca-client may have rebuilt its drivers from scratch, so the runtime forgets what it had cached about that device's bring-up, both the driver's own initialized flag and the system's bring-up record. The next explicit orca device initialize or connect then actually reaches the instrument instead of being skipped as already done.

The runtime also marks an observation gap on every piece of labware sitting at that device, because nobody was watching while the connection was down, and it re-reads the deck if the device is a liquid handler. That re-read runs in the background after orca-client connects. What it does not do is move anything. Homing and bring-up stay behind their own verbs.

A command that was in flight when the connection dropped leaves a device fault on the device. The workflow will not drive a faulted device. Look at the instrument, put it right, then clear the record with orca device clear-fault <name>.

One instrument, one orca-client​

Device names are claimed when orca-client connects. If a name is already held by another connected orca-client, the daemon refuses the newcomer and closes it with code 1002 and a reason naming the device and its current owner.

This is deliberate and it is not a handover. Two orca-clients wired to one instrument is a misconfiguration: both would believe they own the device, and commands would go to whichever connected last. Stop the first orca-client, then start the replacement.

When orca-client connects, the daemon also checks each device's driver against the topology. If they contradict each other, for example because someone swapped a driver class on the bench PC, the daemon closes the connection with 1002 and names the device.

Taking a device by hand​

To drive an instrument yourself while a workflow is running, take it out of the workflow's reach rather than stopping orca-client:

orca device take-control arm_1 --reason "re-teaching the hotel"
orca device release-control arm_1

A thread that tries to use a held device, or to move labware into or out of it, fails until you release it. Without this a workflow can start a move into the device between two of your own commands. orca-client stays connected the whole time. Only the workflow is blocked from using the device.

See also​

  • Devices for the device classes your workflow calls and how capabilities are decided.
  • Topology for declaring the devices orca-client connects.
  • Transporters for arms, translators and how moves are planned.
  • Simulation hierarchy for what each run mode drives, and which ones do not use orca-client.
  • CLI: inspect for the rest of the orca device verbs.