Control a device with Python
Every connector works the same way, whatever instrument it runs. You find the device by name, ask what it can do, then call it. The script below does all of that on a QInstruments BioShake plate shaker. For another instrument, only the module and action names change.
You need the SDK installed and a BioShake connector running in GroundControl. The script heats, so it needs a heated model (the -T variants). No shaker on the bench? Set simulated to true in the connector's configuration and the script runs against its built-in simulator.
import asyncio
from unitelabs.sdk import AsyncApiClient
async def main():
# Connect to your tenant (reads the credentials from .env)
client = AsyncApiClient()
# Find the device by its connector's name in GroundControl
shaker = await client.get_service_by_name(name="QINSTRUMENTS BioShake")
shaking = shaker.shake_controller
temperature = shaker.temperature_controller # heated -T models only
# Ask what it can do: its modules, then the actions of one
print(shaker.modules.keys())
for name, action in shaking.actions.items():
print(name, action.type)
# PROPERTY: read one value
print(await shaking.get_device_specific_maximum_shaking_speed())
print(await shaking.get_shaker_state_with_description())
# CONTROL: make it do something, here heat to 37 °C
await temperature.set_target_temperature(target_temp=37.0)
await temperature.turn_temperature_control_on()
try:
# SENSOR: stream a live value, one reading per second
subscription = await temperature.subscribe_current_temperature()
async with subscription:
for _ in range(5):
print(await anext(subscription))
finally:
# Safe state: switch the heater off even if a reading failed
await temperature.turn_temperature_control_off()
asyncio.run(main())
Run it with uv run control_a_device.py. It prints the modules, the shake controller's actions with their types, the maximum speed and the shaker's state, then five temperature readings as the plate starts to heat.
Every action is one of the three types the comments name:
| Type | What it does | How you call it |
|---|---|---|
PROPERTY | Reads one value | await it. The name usually starts with get_ |
SENSOR | Streams values as they come | Subscribe. The name starts with subscribe_ |
CONTROL | Makes the device do something | await it with its parameters |
To see what a control expects before you call it, print its schema: print(await temperature.set_target_temperature.parameters). The platform's web interface shows the same modules and actions as a form, so you can try one there without code.
Next steps
- Liquid handling as code: the same idea on a liquid handler, which also needs to know what is on its deck.
- BioShake device guide: connector configuration, error messages and more snippets.
- UniteLabs SDK & REST API: each action type in detail, side by side with the REST API.
Last updated