UniteLabs
Tecan FluentControl

Connect & Run a Method

How to connect to the Tecan FluentControl connector and start a FluentControl method.
Different integration model: Unlike Hamilton STAR/Vantage and Agilent Bravo — which expose instrument commands directly through the SDK's typed deck and labware model — FluentControl is driven through a method defined inside the FluentControl software. The SDK prepares and starts that method; FluentControl handles the actual instrument control. If the method is fully configured in FluentControl, no further interaction is needed — the SDK simply triggers it and waits. For dynamic control, the method can include an XML execution channel step, which lets the SDK stream commands into the running method to configure the worktable, register labware, and trigger liquid handling at runtime.

The FluentControl connector exposes two controller interfaces on the Service object. The runtime_controller manages the lifecycle of a named method in the FluentControl software — preparing, starting, and closing it. The execution_channel_controller is an XML message bus that becomes available while the method is running, through which commands are streamed to the instrument. Commands can only be sent through the XML channel while a method is actively executing.

Prerequisites

  • A running Tecan FluentControl instrument with the FluentControl software open
  • A named method configured in the FluentControl software
  • A running Tecan FluentControl connector registered in the UniteLabs platform
  • The UniteLabs SDK installed (see the SDK getting started guide)

Connect to the Connector

Retrieve the FluentControl service by the connector name registered in the platform. The name must match exactly.

from unitelabs.sdk import AsyncApiClient

client = AsyncApiClient()
service = await client.get_service_by_name("Tecan FluentControl")

The returned service object exposes both execution_channel_controller and runtime_controller.

Check and Reset the Channel

Before starting a new session, verify that no XML channel is already open from a previous run. If one is, close it before proceeding.

import asyncio

await asyncio.sleep(2)  # let the system state settle before reading channel status
is_alive = await service.execution_channel_controller.get_is_alive()

if is_alive:
    channel = await service.execution_channel_controller.get_channel()
    print(f"Closing open channel: {channel}")
    await service.execution_channel_controller.finish_command()
Important: If get_is_alive() returns True, FluentControl is still in Advanced Worklist Execution mode from a prior run. Calling prepare_method() in this state will raise an exception — FluentControl cannot accept a new method preparation while the previous execution channel is still open. Call finish_command() first to return it to EditMode.

List Available Methods

Use get_runnable_methods() to retrieve the method names available in the connected FluentControl software. Method names are case-sensitive.

methods = await service.runtime_controller.get_runnable_methods()
print(methods)
# ["plate_prep", "dilution_series", "demo"]

Prepare and Start the Method

Prepare the method by name, then start it. After calling run_method(), wait for the XML channel to become ready before sending any commands.

await service.runtime_controller.prepare_method(method="plate_prep")
await service.runtime_controller.run_method()

# Simple: fixed wait for the XML channel to open (used in the reference implementation)
await asyncio.sleep(3)

# Robust alternative: poll until the channel is ready, with a timeout
# for _ in range(20):
#     if await service.execution_channel_controller.get_is_alive():
#         break
#     await asyncio.sleep(0.5)
# else:
#     raise TimeoutError("XML channel did not open within 10 seconds")
Why the wait?: After run_method(), FluentControl transitions from Idle to Advanced Worklist Execution mode and opens the XML channel. This state transition takes a few seconds on the FluentControl side and is not signalled back to the SDK. The fixed asyncio.sleep(3) works in most environments — increase it to 5 seconds on slower hardware, or replace it with the polling loop above, which waits until get_is_alive() confirms the channel is actually ready.

Close the Method

Closing the session requires two distinct steps, in order.

Step 1 — finish_command() sends the finish signal through the XML execution channel. FluentControl receives it, closes the channel on its side, and returns to EditMode. The instrument is no longer accepting XML commands after this call.

Step 2 — close_method() closes the SDK-level method session. After finish_command() the method has completed on the instrument, but the connector still holds a reference to it; close_method() releases that reference and marks the runtime as idle and ready for the next run.

await service.execution_channel_controller.finish_command()  # close XML channel → EditMode
await service.runtime_controller.close_method()              # release SDK method reference
Important: finish_command() must always be called before close_method(). Calling close_method() while the XML channel is still open leaves FluentControl with an orphaned execution channel that requires a manual restart of the FluentControl software to recover.