We have a STAR set up with a 405 TS plate washer, but the whole system has recently been updated to VENUS 6 and the libraries supporting the integration have evaporated. I’m new to programming integrations- does anyone have experience integrating this plate washer model with liquid handlers? Are there any existing Hamilton libraries that can support this integration out of the box, or do I have to buy Biotek’s LHC software and somehow control the washer via an executable from within VENUS? Any help appreciated!
That thread might be interesting for you: Biotek EL406 Washer - dev discussion - PyLabRobot Forums . I have not worked on the announced 405TS integration into PLR since. I have also never integrated the 405 into a liquidhandler but into our new robotic platform. Currently we are using a rather hacky way there to control it directly via serial interface from python. That saves me from using windows or any 32bit programs. If you go with LHC this solution might be interesting for you: robotlab/labrobots at main · pharmbio/robotlab · GitHub (Have your favorite AI summarize the LHC part for you) Thats the currently running on another platform here.
Hey this is great! Thanks for the direction, I’ll see what solutions I can work out from those suggestions.
The LHC solution seems more… legal.
At least under European law reverse engineering is legal when it enables interoperability (as far as I know)
No really experience w/ biotek washer integration, but with Tecan HydroSpedd with Venus 4.5. We indeed installed the software that control the HydroSpeed (HydroControl) and we got a library from Hamilton that also needed to be installed. Then we access the library via Venus to call a wash program. However, wash program are set-up via HydroControl and have to be saved locally. Try to re-installed the “old” libraries. Maybe they work. If they don’t, it is a good investment -in my opition- to request for an update of the library to Hamilton.
Updating here with my solution, in case anyone finds themselves in a similar situation and want a quick fix.
I obtained a copy of Liquid Handling Control 2.22, allowing me remote control of the plate washer via BTILHCRunner.dll, which came with the software install. I vibecoded a mini console app to build against .NET 3.5 framework, added below. After building the app, I can call the executable (more accurately, I call a .bat file containing the exe path and necessary arguments) from within a VENUS Script command to run the plate washer using whatever .lhc protocol files I want.
This works in my case, where I run a limited number of wash protocols. Maybe there is a more dynamic way to pass arguments, but I’m no expert. Thanks @Stefan_M for the initial direction on this!
using System;
using System.Threading;
using BTILHCRunner;
class Program
{
// RunStatus enum
const short eReady = 1, eNotReady = 2, eBusy = 3, eError = 4, eDone = 5,
ePaused = 7, eStopRequested = 8, eStopping = 9;
const short eOK = 1; // Runner_ReturnCode.eOK
static ClassLHCRunner lhc; // confirmed class name from ildasm (instance methods)
static int Main(string[] args)
{
// Usage: LhcRun.exe "<comms>" "<protocolPath>"
if (args.Length < 2) { Console.Error.WriteLine("args: comms protocolPath"); return 10; }
string comms = args[0];
string protocol = args[1];
lhc = new ClassLHCRunner(); // instance methods confirmed via ildasm -> use new
if (!Ok(lhc.LHC_SetProductName("405 TS/LS"), "SetProductName")) return 11;
if (!Ok(lhc.LHC_SetCommunications(comms), "SetCommunications")) return 12;
lhc.LHC_SetRunnerThreading(1); // REQUIRED: without this the 405 TS/LS
// returns eBusy forever and never runs
if (!Ok(lhc.LHC_TestCommunications(), "TestCommunications")) return 13;
if (!Ok(lhc.LHC_LoadProtocolFromFile(protocol), "LoadProtocol")) return 14;
short rs = lhc.LHC_RunProtocol();
if (rs != eBusy) { Fail("RunProtocol did not return eBusy", rs); return 20; }
// Poll
while (true)
{
Thread.Sleep(500); // no benefit polling faster than 2x/sec
short s = lhc.LHC_GetProtocolStatus();
switch (s)
{
case eReady: Console.WriteLine("DONE OK"); return 0;
case eBusy:
case eDone:
case ePaused:
case eStopRequested:
case eStopping:
continue; // still active
case eNotReady: Fail("step failed to start", s); return 21;
case eError:
short ec = lhc.LHC_GetLastErrorCode();
Console.Error.WriteLine("ERROR " + ec + ": " + lhc.LHC_GetErrorString(ec));
return 22;
default: Fail("unexpected status", s); return 23;
}
}
}
static bool Ok(short code, string where)
{
if (code == eOK) return true;
Console.Error.WriteLine(where + " failed (" + code + "): " + lhc.LHC_GetErrorString(code));
return false;
}
static void Fail(string msg, short s)
{
Console.Error.WriteLine(msg + " (status " + s + ")");
}
}