SpectraDx
pectraDx
SpectraDxlight to insight
← Back to blog
FTIR

Bruker OPUS Python Integration: Guide to All 5 Interfaces

Bruker OPUS Python integration covering all five programmatic interfaces - DDE, Named Pipes, HTTP, OPC, and COM/ActiveX - with working code and examples.

Bruker OPUS Python Integration: Guide to All 5 Interfaces

If you are building anything beyond a manual benchtop workflow with a Bruker FTIR spectrometer, you need programmatic access to OPUS. Manual operation - click "Measure Background," wait, click "Measure Sample," wait, export the file, open it in another application - does not scale. It does not belong in a clinical workflow, a high-throughput QC line, or any deployment where a human operator should not be the bottleneck between the instrument and the result.

OPUS (currently v9.3) is Bruker's proprietary spectroscopy software. It controls the instrument, acquires spectra, and stores results in its own binary format. Every Bruker FTIR ships with it. And buried inside OPUS are five distinct programmatic interfaces, each designed for different integration scenarios, each with different trade-offs.

This guide covers all five. We will walk through working code, explain the constraints, and give you a decision framework for choosing the right one. If you are looking for a hands-on Python tutorial, see our companion article on automating FTIR measurements with Python.


Why This Matters

Consider what happens in a clinical diagnostic workflow built around FTIR spectroscopy. A tissue sample arrives. A clinician places it on the ATR crystal of a Bruker Alpha II. The system needs to:

  1. Trigger a background measurement (if stale)
  2. Acquire the sample spectrum
  3. Read the resulting spectral data
  4. Run it through a classification model
  5. Deliver the result to the clinician and the EHR

Steps 1 through 3 require talking to OPUS. There is no alternative - OPUS owns the instrument. The question is how you talk to it.


Interface 1: DDE (Dynamic Data Exchange)

DDE is the most practical interface for Python-based automation. It is the interface that most developers reach for first, and for good reason: it works, it is well-supported by the brukeropus library, and it covers the most common use cases.

What DDE Is

Dynamic Data Exchange is a Windows IPC (inter-process communication) protocol from the early 1990s. It predates COM, predates .NET, and somehow still works perfectly well for instrument control. OPUS registers itself as a DDE server when it starts. Your application connects as a DDE client and sends command strings.

Constraints

  • Same PC only. DDE is a local IPC protocol. Your automation code must run on the same Windows machine as OPUS.
  • OPUS must be running. DDE connects to a running OPUS instance - it cannot start OPUS for you.
  • Windows only. DDE is a Windows-native protocol. No Linux, no macOS.
  • Single client. Only one DDE client can connect to OPUS at a time.

Working Code

The brukeropus Python library wraps the DDE interface cleanly:

from brukeropus import opus_dde
 
# Connect to the running OPUS instance
opus = opus_dde.OPUSDde()
 
# Trigger a background measurement
opus.measure_ref()
 
# Trigger a sample measurement using the current experiment
opus.measure_sample()
 
# Send a raw OPUS command string
# This gives you access to the full OPUS command set
opus.raw_command('MeasureSample', {'EXP': 'MyExperiment.xpm'})
 
# Unload a file from the OPUS workspace
opus.unload_file('C:/Data/sample.0')

The OPUSDde class handles the connection lifecycle, command serialization, and response parsing. Under the hood, it is calling win32ui.dde to establish the DDE conversation with OPUS.

For reading acquired spectra back into Python, the same library provides file parsing:

from brukeropus import read_opus
 
opus_file = read_opus('C:/Data/sample.0')
 
# Access absorbance data
wavenumbers = opus_file.a.x    # numpy array of wavenumber values
absorbance = opus_file.a.y     # numpy array of absorbance values
 
# Access metadata
print(opus_file.params)        # measurement parameters

When to Use DDE

DDE is the right choice when you are writing Python automation that runs on the same PC as the instrument. It is the path of least resistance for proof-of-concept integrations, small clinical deployments, and research automation. Our Python FTIR tutorial walks through a complete DDE-based workflow.


Interface 2: Named Pipes

Named Pipes is a lower-level IPC mechanism than DDE, also constrained to the local machine. OPUS exposes a named pipe server that accepts command messages in a binary protocol.

What Named Pipes Are

A named pipe is a one-to-one communication channel between two processes on the same Windows machine (or, in theory, across a network - though OPUS does not support remote named pipe connections). Unlike DDE, which uses a text-based command protocol, named pipes carry raw binary data.

Constraints

  • Same PC only. Same constraint as DDE.
  • Binary protocol. You must serialize and deserialize OPUS command structures yourself. There is no high-level Python wrapper.
  • C/C++ preferred. The OPUS OEM DLL Manual (v6) documents the pipe protocol with C struct definitions. Calling from Python requires ctypes or cffi and intimate knowledge of the message format.
  • Less community support. Unlike DDE, there is no popular open-source library wrapping the named pipe interface.

Working Code

The pipe name follows a convention based on the OPUS process:

// C/C++ example - connecting to the OPUS named pipe
#include <windows.h>
 
HANDLE hPipe = CreateFile(
    TEXT("\\\\.\\pipe\\OPUS_Pipe"),
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
);
 
if (hPipe == INVALID_HANDLE_VALUE) {
    // OPUS is not running or pipe is not available
    return -1;
}
 
// Construct a command message per the OPUS OEM DLL protocol
// See OPUS OEM DLL Manual v6 for struct definitions
OPUS_CMD cmd;
cmd.command_id = CYCM_MEASURE_SAMPLE;
cmd.param_count = 0;
 
DWORD bytesWritten;
WriteFile(hPipe, &cmd, sizeof(cmd), &bytesWritten, NULL);
 
// Read response
OPUS_RESPONSE response;
DWORD bytesRead;
ReadFile(hPipe, &response, sizeof(response), &bytesRead, NULL);

In Python, you can connect to the named pipe using win32file:

import win32file
import struct
 
# Open the OPUS named pipe
handle = win32file.CreateFile(
    r'\\.\pipe\OPUS_Pipe',
    win32file.GENERIC_READ | win32file.GENERIC_WRITE,
    0,
    None,
    win32file.OPEN_EXISTING,
    0,
    None
)
 
# At this point you need to construct binary command messages
# per the OPUS OEM DLL specification
# This is significantly more work than DDE for equivalent functionality

When to Use Named Pipes

Named Pipes make sense when you are building a C/C++ application that needs tight, low-latency control of OPUS, or when you are integrating with an existing C/C++ codebase. For most other cases, DDE is simpler and equally capable.


Interface 3: HTTP Server

This is the least documented interface, and arguably the most interesting one for modern architectures. OPUS includes an embedded HTTP server that can be enabled through configuration. Once active, it exposes instrument control and data retrieval over HTTP - the closest thing OPUS has to a REST API.

What the HTTP Server Provides

When enabled, OPUS listens on a configurable port (default varies by version) and accepts HTTP requests for:

  • Triggering measurements
  • Retrieving spectral data
  • Querying instrument status
  • Loading and unloading files

Constraints

  • Not publicly documented. Bruker does not publish the HTTP API specification. The endpoints and request formats must be discovered through network inspection or Bruker support channels.
  • Must be explicitly enabled. The HTTP server is not active by default. It requires configuration changes in OPUS settings.
  • Network accessible. Unlike DDE and Named Pipes, the HTTP server can be accessed from other machines on the network. This is both its greatest advantage and a security consideration.
  • No authentication by default. The HTTP server, when enabled, does not include authentication. Network-level security (firewalls, VLANs) is essential.

Working Code

Because the API is not publicly documented, the following is based on observed behavior and may vary between OPUS versions:

import requests
 
OPUS_HOST = "192.168.1.100"  # IP of the OPUS workstation
OPUS_PORT = 6200             # Port configured in OPUS settings
 
base_url = f"http://{OPUS_HOST}:{OPUS_PORT}"
 
# Query instrument status
response = requests.get(f"{base_url}/api/status")
print(response.json())
 
# Trigger a measurement
response = requests.post(f"{base_url}/api/measure", json={
    "type": "sample",
    "experiment": "MyExperiment.xpm"
})
 
# Retrieve the last measurement result
response = requests.get(f"{base_url}/api/result/latest")
spectral_data = response.json()

The exact endpoint paths and payload schemas depend on OPUS version. If you pursue this interface, use browser developer tools or Wireshark to inspect the traffic while operating OPUS through its web-based interface (available in newer OPUS versions).

When to Use the HTTP Server

The HTTP interface is compelling when your automation software runs on a different machine than OPUS - for example, a central workflow server managing multiple instruments across a lab. It is also the most natural fit for web-based applications. The downside is the lack of official documentation and the risk that Bruker changes the API between versions without notice.


Interface 4: OPC (OLE for Process Control)

OPC is an industrial automation standard, widely used in manufacturing and process control. OPUS supports OPC for integration with SCADA systems, LabVIEW, and industrial automation platforms.

What OPC Provides

OPC defines a standardized way for industrial software to exchange data. OPUS acts as an OPC server, exposing instrument parameters, measurement status, and spectral data as "tags" that OPC clients can read and write.

Constraints

  • Designed for industrial automation. OPC is overkill if you just want to trigger a measurement from Python. It makes sense when OPUS is one node in a larger industrial control system.
  • OPC DA (Classic) vs. OPC UA. OPUS primarily supports the older OPC DA (DCOM-based) standard. OPC UA (the modern, platform-independent version) support varies by OPUS version. Check with Bruker for your specific configuration.
  • DCOM configuration. OPC DA relies on Windows DCOM, which is notoriously difficult to configure correctly across machines. Firewalls, permissions, and DCOM security settings must all be aligned.
  • LabVIEW integration. OPC is the natural path if your existing automation is built in LabVIEW, which has native OPC client support.

Working Code

Using the OpenOPC Python library for OPC DA:

import OpenOPC
 
# Connect to the OPUS OPC server
opc = OpenOPC.client()
opc.connect('Bruker.OPUS.OPC')
 
# Read instrument status
status = opc.read('OPUS.Instrument.Status')
print(f"Instrument status: {status}")
 
# Read the last measured spectrum (if exposed as OPC tags)
wavenumber_start = opc.read('OPUS.Spectrum.WavenumberStart')
wavenumber_end = opc.read('OPUS.Spectrum.WavenumberEnd')
 
# Write to trigger a measurement
opc.write(('OPUS.Command.MeasureSample', True))
 
# List all available OPC tags from OPUS
tags = opc.list('OPUS.*')
for tag in tags:
    print(tag)
 
opc.close()

For OPC UA (if supported by your OPUS version):

from opcua import Client
 
client = Client("opc.tcp://localhost:4840")
client.connect()
 
root = client.get_root_node()
# Navigate the OPUS node tree to find measurement controls
opus_node = root.get_child(["0:Objects", "2:OPUS"])
 
client.disconnect()

When to Use OPC

OPC is the right choice when OPUS sits inside a larger industrial automation ecosystem - a pharmaceutical production line, a refinery quality control system, or any environment where LabVIEW, SCADA, or PLC-based controllers are already managing other instruments via OPC.


Interface 5: COM/ActiveX (VBToolkit Pro)

COM/ActiveX provides the most complete programmatic access to OPUS functionality. It exposes OPUS as a COM automation server with a full object model - experiments, measurements, data blocks, processing commands.

What COM/ActiveX Provides

Through the COM interface, you get an object-oriented API to OPUS. You can enumerate experiments, configure measurement parameters at a granular level, process spectra using OPUS's built-in algorithms, and access data blocks directly.

Constraints

  • Requires VBToolkit Pro license. This is a paid add-on from Bruker, separate from the base OPUS license. It is not cheap.
  • COM registration. OPUS must register its COM server on the machine. This happens during installation when VBToolkit Pro is included.
  • .NET and VBA preferred. COM interop is most natural from C#, VB.NET, or VBA (Excel macros). Python can access COM via comtypes or win32com, but the experience is less polished.
  • Same PC or DCOM. Like OPC DA, remote COM access requires DCOM configuration.

Working Code

From C# (.NET):

using System;
using System.Runtime.InteropServices;
 
// Reference the OPUS COM type library
// (added via Visual Studio "Add Reference" > COM > "Bruker OPUS Automation")
dynamic opus = Activator.CreateInstance(
    Type.GetTypeFromProgID("OPUS.Application"));
 
// Connect to OPUS
opus.Connect();
 
// Load an experiment
dynamic experiment = opus.LoadExperiment(@"C:\OPUS\Experiments\ATR.xpm");
 
// Trigger a measurement
dynamic result = opus.MeasureSample(experiment);
 
// Access the result spectrum
double[] wavenumbers = result.GetXData();
double[] absorbance = result.GetYData("AB");  // AB = absorbance block
 
Console.WriteLine($"Spectrum: {wavenumbers.Length} points");
Console.WriteLine($"Range: {wavenumbers[0]} - {wavenumbers[wavenumbers.Length-1]} cm-1");
 
// Disconnect
opus.Disconnect();

From Python using win32com:

import win32com.client
 
# Create the OPUS COM object
opus = win32com.client.Dispatch("OPUS.Application")
 
# Connect
opus.Connect()
 
# Load experiment and measure
experiment = opus.LoadExperiment(r"C:\OPUS\Experiments\ATR.xpm")
result = opus.MeasureSample(experiment)
 
# Access data
wavenumbers = list(result.GetXData())
absorbance = list(result.GetYData("AB"))
 
print(f"Acquired {len(wavenumbers)} data points")
 
opus.Disconnect()

When to Use COM/ActiveX

COM/ActiveX is the right choice when you are building a full-featured desktop application in C# or VB.NET, need access to OPUS's internal processing algorithms (not just raw data), and have the budget for the VBToolkit Pro license. It provides the deepest integration but at the highest cost and complexity.


Comparison Table

InterfaceProtocolLocal/RemoteBest LanguageLicense RequiredBest For
DDEWindows DDELocal onlyPythonBase OPUSPython automation, clinical workflows
Named PipesWindows IPCLocal onlyC/C++Base OPUSLow-level C/C++ integration
HTTP ServerHTTPRemote capableAnyBase OPUSMulti-instrument, web-based systems
OPCOPC DA/UARemote (DCOM)LabVIEWBase OPUSIndustrial automation, SCADA
COM/ActiveXCOM/DCOMLocal (DCOM for remote)C#, VB.NETVBToolkit Pro (paid)Full-featured .NET desktop apps

Decision Framework: Which Interface Should You Use?

Start with these questions:

1. What language are you writing in?

  • Python → DDE (via brukeropus)
  • C/C++ → Named Pipes or DDE
  • C# / VB.NET → COM/ActiveX (if you have VBToolkit Pro) or DDE
  • LabVIEW → OPC
  • JavaScript / web stack → HTTP Server

2. Does your code run on the same machine as OPUS?

  • Yes → DDE is the simplest path
  • No → HTTP Server is the only practical remote option (OPC DA over DCOM is fragile)

3. Is OPUS one instrument in a larger industrial system?

  • Yes, with existing OPC infrastructure → OPC
  • Yes, without OPC → HTTP Server
  • No, standalone instrument → DDE

4. Do you need OPUS's built-in processing algorithms?

  • Yes → COM/ActiveX (VBToolkit Pro) exposes them directly
  • No, you will process spectra in your own code → DDE or HTTP Server

For most clinical and research workflows, DDE via brukeropus is the right starting point. It is free (included with base OPUS), well-supported by the Python community, and covers the core operations: trigger measurements, read results, and control the experiment. Start there. Graduate to HTTP Server if you need remote access or multi-instrument orchestration.


Reading OPUS Files (Without Controlling OPUS)

Controlling the instrument is one problem. Reading the data files is a separate one. Even if you never need to trigger a measurement programmatically, you may need to parse OPUS's proprietary file format.

OPUS File Format

OPUS stores spectra in proprietary binary files with numeric extensions: .0, .1, .2, and so on. Each file contains multiple data blocks - absorbance, transmittance, interferogram, reference spectrum, and metadata - all packed into a single binary container. The format is not publicly documented by Bruker. For a broader look at spectral file formats across vendors, see our guide to spectral data formats and interoperability.

OPUS can also export to standard formats:

  • JCAMP-DX (.dx, .jdx) - ISO/IUPAC standard for spectral data. Text-based, widely supported.
  • CSV - plain text, but loses metadata.
  • SPC (Galactic/Thermo) - another proprietary format, but more widely supported than OPUS.

Python Libraries for OPUS Files

Several open-source libraries reverse-engineer the OPUS binary format:

brukeropus - the most complete option. Handles reading and DDE control:

from brukeropus import read_opus
 
opus_file = read_opus('sample.0')
 
# List all data blocks in the file
print(opus_file.data_keys)   # e.g., ['a', 't', 'r', 'igsm', 'igrf']
 
# Absorbance spectrum
wavenumbers = opus_file.a.x   # numpy array
absorbance = opus_file.a.y    # numpy array
 
# Transmittance spectrum
transmittance = opus_file.t.y
 
# Reference (background) interferogram
ref_interferogram = opus_file.igrf.y
 
# Metadata
print(opus_file.params)

brukeropusreader - lighter weight, read-only:

from brukeropusreader import read_file
 
data = read_file('sample.0')
 
# Access data blocks by their OPUS block type codes
absorbance = data["AB"]       # absorbance spectrum
wavenumbers = data["AB Data Parameter"]["FXV"]  # first x value

opusFC - C-based reader with Python bindings. Fast for batch processing:

import opusFC
 
# List blocks in the file
blocks = opusFC.listContents('sample.0')
for block in blocks:
    print(f"Type: {block.blocktype}, Points: {block.npt}")
 
# Read a specific block
data = opusFC.getOpusData('sample.0', blocks[0])
wavenumbers = data.x
absorbance = data.y

spectrochempy - full-featured spectroscopy framework, not OPUS-specific:

import spectrochempy as scp
 
# Read OPUS files directly
dataset = scp.read_opus('sample.0')
 
# Built-in preprocessing
dataset_corrected = scp.baseline_correction(dataset)
dataset_normalized = scp.normalize(dataset_corrected)

Which Library Should You Use?

Use caseRecommended library
Building automation that also controls the instrumentbrukeropus (handles both reading and DDE)
Just parsing OPUS files, need it lightweightbrukeropusreader
High-volume batch processing, need speedopusFC
Full spectroscopic analysis workflowspectrochempy

From Interfaces to Clinical Workflows

Knowing how to talk to OPUS is necessary but not sufficient for a clinical deployment. The programmatic interface is the lowest layer. On top of it you need several additional capabilities.

Patient context. A spectrum is meaningless without knowing which patient it belongs to. The system needs MRN/accession number tracking, barcode scanning, and worklist management.

Measurement orchestration. Background checks, quality control validation, automatic retries on failed acquisitions, and audit logging of every measurement event.

Classification pipeline. The raw spectrum goes through preprocessing (baseline correction, normalization) and into a trained ML model. The output is a clinical classification with confidence scores. For details on building this pipeline, see Building AI Pipelines for Spectral Classification.

Result delivery. The classification must reach the clinician (on-screen result) and the EHR (HL7v2 ORU^R01 message or FHIR DiagnosticReport). See our clinical workflow architecture article for the full system design.

Regulatory compliance. If the software provides a diagnostic classification, it is likely a Software as a Medical Device (SaMD) under FDA/EU MDR. IEC 62304 software lifecycle, risk management (ISO 14971), and clinical validation all apply.

This is what SpectraDx builds. The platform handles the full vertical - from instrument interface to HL7 output - so that teams building spectroscopy-based diagnostics can focus on their clinical application instead of reinventing integration plumbing. We have already solved the DDE timing issues, the OPUS file locking edge cases, the background measurement staleness logic, and the dozens of other details that only surface when you deploy to a real clinical environment.


Further Reading


SpectraDx is clinical workflow software for spectroscopy-based diagnostics. We handle the integration layer between your spectrometer and your clinician. Learn more or get in touch.

Frequently Asked Questions

Yes. The most common approach is the DDE interface via the brukeropus Python library, which lets you trigger background measurements, acquire sample spectra, and read results programmatically. For remote access or multi-instrument setups, OPUS also exposes an HTTP REST API that any language can call.

DDE is the best starting point for Python-based automation on the same machine as OPUS — it is free, well-documented, and covers core operations. The HTTP Server API is the better choice for remote access, web-based systems, or orchestrating multiple instruments from a central application.

Install the brukeropus library with pip install brukeropus and use read_opus() to extract absorbance, transmittance, and interferogram data as NumPy arrays. For lighter-weight read-only parsing, brukeropusreader and opusFC are also available. All three libraries reverse-engineer the proprietary OPUS binary format.

Yes. Recent versions of OPUS include an HTTP REST API that allows remote instrument control over a network. OPC DA/UA is another remote option for industrial automation environments, though it requires more infrastructure. DDE and Named Pipes are local-only interfaces.

SpectraDx builds clinical workflow software for spectroscopy-based diagnostics.

The layer between the spectrometer and the clinician. Instrument control, patient workflow, ML classification, HL7/FHIR output, and billing — in one platform.

Get articles like this in your inbox.

Monthly technical resources for spectroscopy professionals. No marketing fluff.