Skip to content
Elutrolab
Get a quoteRequest a quote

SiLA 2, OPC UA LADS and serial: lab instrument integration standards

SiLA 2, OPC UA LADS, SCPI and plain serial protocols compared on transport, discovery, typing, tooling and effort, with a tested SiLA 2 wrapper for a serial pump.

Published
Reading time
9 min
Category
Engineering
Sources
11

SiLA 2 is an open lab automation standard in which an instrument, or a driver for it, runs a server that exposes typed "Features" over gRPC (HTTP/2 and Protocol Buffers), with automatic discovery on the local network and observable commands for long-running tasks. OPC UA LADS (OPC 30500, released November 2023) is an OPC UA companion specification that models a lab device as a tree of functional units, functions and programs. Many instruments still speak a plain text protocol over serial or TCP. For a lab, the practical route is usually to keep the native protocol and wrap it in SiLA 2 or LADS when an orchestrator needs it; for an instrument maker, a documented text protocol is the minimum, and a native SiLA 2 or LADS server is a market decision.

Key points

  • SiLA 2 1.0 was released in September 2019 and 1.1 in March 2022; it requires TLS (except inside a protected network) and mDNS/DNS-SD discovery that cannot be switched off.
  • LADS 1.0.0 was published on 30 November 2023 by a joint working group of the OPC Foundation, SPECTARIS and VDMA.
  • Allotrope and AnIML standardise results, not control. Use them alongside whichever control standard you choose.
  • SCPI (SCPI-99, built on IEEE 488.2) is the common language of electronic test equipment; many chemistry instruments use vendor text protocols instead.
  • Wrapping a serial instrument in a SiLA 2 server takes one Feature Definition file, generated code and a few dozen lines of glue. We built and tested one below.

What is SiLA 2?

SiLA ("Standardization in Lab Automation") is an industry consortium backed by life science companies, device manufacturers and software suppliers. SiLA 2 is specified in three parts: Part A (concepts and core), Part B (mapping to the wire protocol) and Part C (index of standard Features). The version history in Part A lists release 1.0 on 30 September 2019, release 1.1 on 19 March 2022 and a working draft dated 27 January 2025. Version 1.1 added a server-initiated connection method, so that an instrument behind a firewall can connect out to a cloud client.

The main concepts:

  • SiLA Server and SiLA Client. The server is the instrument or its driver; the client is the orchestrator, LIMS or script.
  • Features. Each Feature describes one behaviour, such as controlling a temperature. Every server must implement the SiLA Service Feature, which reports the server's identity and its other Features.
  • Commands and properties. Commands are observable or unobservable. Part A recommends an observable command for anything whose progress is worth watching, such as measuring a spectrum: the server returns a command execution UUID, and the client subscribes to progress, estimated remaining time and intermediate responses. Properties can be read once or subscribed to.
  • Defined execution errors with identifiers, so a client can tell "temperature not reachable" from a crash.
  • Feature Definition Language (FDL). Features are written as XML files validated against the schema in the sila_base repository, with data types, units and constraints.

Part B maps all of this to gRPC. It requires TLS between clients and servers unless the communication is entirely inside a separated network with encryption at the gateway. Every server must implement multicast DNS (RFC 6762) and DNS-SD (RFC 6763) under the service type _sila._tcp, with the server UUID as the instance name, and it must not be possible to disable discovery.

Tooling. The SiLA2 GitLab group hosts reference implementations in Python, Java, C#, C++, JavaScript and Rust, a Universal SiLA Client, and a Tecan SDK. The Python package sila2 (0.14.0, December 2025) is now marked unmaintained and points to UniteLabs' MIT-licensed SiLA Python library (unitelabs-sila) and connector framework (unitelabs-cdk). The community "Awesome SiLA" list includes servers for CETONI syringe pumps, plate washers, dispensers and robot arms, several of them drivers that wrap an instrument's existing USB or vendor interface.

What is OPC UA LADS?

LADS, the Laboratory and Analytical Device Standard, is an OPC UA companion specification. OPC 30500-1, version 1.0.0, was published on 30 November 2023 as "Part 1: LADS Base System", the first of a planned series. Its scope states it was developed by the OPC Foundation, SPECTARIS and VDMA, and the working group page describes a device-type-agnostic model built on the OPC UA Devices specification with patterns from the Analyser Devices (ADI) specification.

The model, from the specification's overview:

  • Device: nameplate, installation date, condition monitoring, calibration and validation status.
  • Components: hardware parts such as a lid, rotor, drive or compressor.
  • Functional units: "aggregations of functions designed to achieve a specific outcome".
  • Functions: sensors, controllers, actuators, timers and similar.
  • Program manager: program templates (methods), runs and result data.
  • State machines for the device, functional units and control functions.

Open-source starting points live in the opcua-lads GitHub organisation: a Node.js workshop, C# and open62541 examples, a Python client, and a collection of example servers, some annotated with Allotrope ontologies. OPC UA also brings mature subscriptions and security, and it already appears in analytical software: Agilent's Online LC Monitoring Software, for example, uses OPC UA to exchange data with sampling devices.

Data standards: Allotrope and AnIML

Control standards move commands; data standards make the results readable later. The Allotrope Framework has four parts: ontologies (AFO), data models (ADM), a data format (ADF) and Allotrope Simple Models (ASM), a JSON representation that is easy to produce from any language. Benchling's open-source allotropy library converts many instrument export files to ASM. AnIML is an XML format developed under ASTM, combining a core schema with technique definitions for each analytical method; SiLA 2 Part A includes guidance on when to return results as AnIML rather than as a SiLA structure. Whatever control route you choose, store results in one of these forms with the sample and method metadata attached.

SCPI and plain text protocols

SCPI (Standard Commands for Programmable Instruments; current document SCPI-99, May 1999) builds on IEEE 488.2-1987, which defined common commands such as *IDN?. SCPI adds a hierarchical command tree and an error queue read with SYSTem:ERRor[:NEXT]?. The IVI Foundation has maintained it since the SCPI Consortium merged into IVI in late 2003. It is widely used in oscilloscopes, power supplies and meters, and some lab devices borrow its style.

Many pumps, valves, autosamplers and balances use a vendor-specific text protocol: a command line in, a reply line out, over RS-232, a USB virtual COM port or a TCP socket. There is no discovery and no type system, but anything that can open a port can drive it, as shown in controlling serial lab instruments from Python.

Comparison table

SiLA 2OPC UA LADSSCPIPlain serial or TCP text
TransportgRPC over HTTP/2, TLS requiredOPC UA client-serverIEEE 488, USB, LAN or serialRS-232, USB virtual COM, TCP
DiscoveryMandatory mDNS/DNS-SDOPC UA discovery and address-space browsingNone beyond *IDN?None
TypingTyped parameters, units, constraints in FDLTyped information modelDefined syntax, mostly numericStrings, vendor-defined
Long-running actionsObservable commands with progressFunctions, state machines, program managerPolling, status registersPolling
ErrorsDefined execution errorsOPC UA status codes and eventsError queueVendor error replies
ToolingReference SDKs in six or more languages, code generator, universal clientGeneral OPC UA SDKs plus LADS examplesVISA, PyVISA, vendor driversAny serial or socket library
Maturity in labsReleased 2019; vendor SDKs and many community driversReleased November 2023; early implementationsDecades in test and measurementVery common
Effort for an instrument maker (our estimate)Medium to high: gRPC, TLS, mDNS on the device or a gatewayHigh: OPC UA server and information modelLow to mediumLow
Effort for an integrator (our estimate)Low if a server existsLow if a server existsLowOne driver per device

How to choose

For a lab

  • A few instruments, your own scripts: use the native protocol with a small driver class per instrument. No standard is needed.
  • A scheduler or orchestrator that speaks SiLA 2: use vendor SiLA servers where they exist and wrap the rest yourself, as below. This is also the common route in self-driving labs that mix vendors.
  • An OPC UA plant or PAT environment: prefer LADS or vendor OPC UA servers so the lab devices appear in the same system as the reactors.
  • Always: decide where results go (ASM or AnIML) before the first campaign, not after.

For an instrument maker

  1. Publish a documented, versioned text protocol with explicit status queries and error codes. It costs little and lets every user integrate the instrument.
  2. Ship a reference driver, for example a small Python class, with tests against a simulated instrument.
  3. Add a SiLA 2 or LADS server when customers ask for it, either on the instrument (needs a network stack, TLS and mDNS) or as a gateway on a small computer next to it. For a microcontroller-based device with only a serial port, the gateway is the realistic option. The OEM integration checklist covers the other interface decisions.

Worked architecture: wrapping a serial instrument in a SiLA 2 server

The target is the fictional PX-1 syringe pump from the Python guide: ASCII lines terminated by CR LF, STATUS? returning OK IDLE or OK BUSY 40 (percent done), DISPENSE 1.000 to dispense 1 mL, and ERR <code> <text> on failure.

Orchestrator (SiLA Client)
   │  gRPC over HTTP/2, TLS, found via mDNS
SiLA Server on a PC or small computer
   ├─ Feature implementation  (maps commands, properties and errors)
   ├─ Driver class            (one lock, timeouts, logging)
   └─ pyserial
   │  USB virtual COM port or RS-232
PX-1 pump

1. Write the Feature Definition. One observable command with a typed, constrained parameter, one observable property and one defined error. This file validates against the FeatureDefinition.xsd schema in sila_base:

<?xml version="1.0" encoding="utf-8"?>
<Feature SiLA2Version="1.0" FeatureVersion="1.0" Originator="com.example" Category="pumps"
         xmlns="http://www.sila-standard.org"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.sila-standard.org https://gitlab.com/SiLA2/sila_base/raw/master/schema/FeatureDefinition.xsd">
  <Identifier>SyringePumpController</Identifier>
  <DisplayName>Syringe Pump Controller</DisplayName>
  <Description>Dispense from a fictional PX-1 syringe pump that is driven over a serial port.</Description>
  <Command>
    <Identifier>Dispense</Identifier>
    <DisplayName>Dispense</DisplayName>
    <Description>Dispense a volume at the current flow rate. Completes when the pump reports idle.</Description>
    <Observable>Yes</Observable>
    <Parameter>
      <Identifier>Volume</Identifier>
      <DisplayName>Volume</DisplayName>
      <Description>Volume to dispense, in millilitres.</Description>
      <DataType>
        <Constrained>
          <DataType><Basic>Real</Basic></DataType>
          <Constraints>
            <Unit>
              <Label>mL</Label>
              <Factor>0.000001</Factor>
              <Offset>0</Offset>
              <UnitComponent><SIUnit>Meter</SIUnit><Exponent>3</Exponent></UnitComponent>
            </Unit>
            <MinimalExclusive>0</MinimalExclusive>
            <MaximalInclusive>4</MaximalInclusive>
          </Constraints>
        </Constrained>
      </DataType>
    </Parameter>
    <DefinedExecutionErrors><Identifier>PumpFault</Identifier></DefinedExecutionErrors>
  </Command>
  <Property>
    <Identifier>PumpStatus</Identifier>
    <DisplayName>Pump Status</DisplayName>
    <Description>Status line as reported by the pump, for example "IDLE" or "BUSY".</Description>
    <Observable>Yes</Observable>
    <DataType><Basic>String</Basic></DataType>
  </Property>
  <DefinedExecutionError>
    <Identifier>PumpFault</Identifier>
    <DisplayName>Pump Fault</DisplayName>
    <Description>The pump answered with an error code. The message contains the pump's reply.</Description>
  </DefinedExecutionError>
</Feature>

2. Generate the server package. With the sila2 package (the UniteLabs framework has its own equivalent):

pip install "sila2[codegen,cryptography]" pyserial
sila2-codegen new-package -n px1_sila -o px1_sila SyringePumpController-v1_0.sila.xml

This writes the Protocol Buffers file, base classes, a client, a server class and an implementation stub.

3. Fill in the implementation. The glue is short because the driver class does the serial work:

import os
import time
from datetime import timedelta

from px1 import Pump, PumpError  # the driver class from the pyserial guide
from ..generated.syringepumpcontroller import Dispense_Responses, PumpFault, SyringePumpControllerBase


class SyringePumpControllerImpl(SyringePumpControllerBase):
    def __init__(self, parent_server) -> None:
        super().__init__(parent_server=parent_server)
        self.Dispense_default_lifetime_of_execution = timedelta(minutes=30)
        self.pump = Pump.open(os.environ.get("PX1_PORT", "/dev/ttyACM0"))
        # One thread polls the pump and feeds the observable property.
        self.run_periodically(self._poll_status, delay_seconds=1.0)

    def _poll_status(self) -> None:
        self.update_PumpStatus(self.pump.status())

    def Dispense(self, Volume: float, *, metadata, instance) -> Dispense_Responses:
        instance.begin_execution()
        try:
            self.pump.query(f"DISPENSE {Volume:.3f}")
            while True:
                reply = self.pump.status()  # "OK BUSY 40" or "OK IDLE"
                if reply.startswith("OK IDLE"):
                    break
                instance.progress = int(reply.split()[2]) / 100
                time.sleep(0.5)
        except PumpError as error:
            raise PumpFault(str(error))
        return Dispense_Responses()

4. Run it. PX1_PORT=/dev/ttyACM0 python -m px1_sila --port 50052 --ca-export-file ca.pem starts the server with TLS and discovery; without your own certificate it generates a self-signed one and writes the CA to ca.pem for clients. Use --insecure only on a bench network.

We ran this against a fake PX-1 on a pseudo-terminal. A client saw the PumpStatus property, watched Dispense(Volume=1.0) report progress rising from 0 to about 0.75 before completing, received the pump's ERR 4 reply as the defined error PumpFault, and had Volume=5.0 rejected with a validation error ("Constraint violated: MaximalInclusive(4.0)") before the pump saw anything.

How serial concepts map to SiLA:

Serial protocolSiLA 2
Status query polled by a scriptObservable property, polled once by the server
Action command plus "poll until idle"Observable command with progress
ERR <code> <text> replyDefined execution error
Range check in your scriptConstraint in the Feature Definition
One script owns the portOne server owns the port; clients share it

Practical pitfalls: mDNS does not cross routed subnets without help; certificate handling needs a plan before you have ten servers; and the server, not each client, must own the serial port. Keep unit conversions in one place, in the Feature Definition.

Where the AS-48 stands

The AS-48 is controlled today through a documented plain-text command set over a USB-C virtual COM port, which places it in the last column of the table. Elutrolab does not offer a SiLA 2 or LADS server, and none has been decided. Because the protocol is documented, users can wrap it the way the PX-1 is wrapped above, on a PC or a small computer next to the sampler.

Frequently asked questions

What is SiLA 2?
SiLA 2 is an open lab automation standard in which an instrument or its driver runs a SiLA Server that exposes typed Features (commands, properties and errors) over HTTP/2 and Protocol Buffers, the gRPC wire format. Servers advertise themselves on the local network with mDNS and DNS-SD.
What is the difference between SiLA 2 and OPC UA LADS?
SiLA 2 describes what a device can do as a set of callable Features and comes from the lab automation community. OPC UA LADS (OPC 30500, 2023) models the device itself as an OPC UA information model of functional units, functions and programs, and comes from the OPC Foundation, SPECTARIS and VDMA.
Is SiLA 2 free to use?
Yes. SiLA describes its standards as free and open, the specification documents are licensed CC BY-SA 4.0, and the reference implementations are open source on GitLab.
Does SiLA 2 replace serial or SCPI protocols?
Usually not. Many SiLA 2 servers are drivers that run on a PC or small computer and talk to the instrument over its native serial, USB or TCP protocol.
Which Python library should I use for SiLA 2?
The SiLA working group's sila2 package (0.14.0) is now marked unmaintained and points to UniteLabs' MIT-licensed SiLA Python library and connector framework. The architecture in this post is the same with either.

Sources

  1. 01SiLA 2 Part (A): Overview, Concepts and Core Specification (working draft, January 2025)
  2. 02SiLA 2 Part (B): Mapping Specification
  3. 03SiLA: Standards overview
  4. 04SiLA 2 reference implementations and sila_base on GitLab
  5. 05sila2 Python package documentation
  6. 06OPC Foundation: OPC 30500-1, OPC UA for Laboratory and Analytical Devices (LADS), Part 1, v1.0.0
  7. 07OPC Foundation: LADS joint working group
  8. 08opcua-lads: open-source LADS examples on GitHub
  9. 09Allotrope Foundation: Allotrope Framework
  10. 10AnIML: Analytical Information Markup Language
  11. 11IVI Foundation: SCPI-99, Standard Commands for Programmable Instruments
All articles