InstroDMM
InstroDMM is a hardware abstraction layer (HAL) that provides a unified interface for SCPI-based digital multimeters. The category class defines the vendor-independent API (set_measurement_function, read, set_range, …). A vendor-specific driver (e.g. Agilent34401A, Keithley2400) owns its connection details and translates those calls into vendor commands.
Supported Vendors
- Agilent / HP / Keysight: 34401A and compatible DMMs via SCPI/VISA (
Agilent34401A) - Keithley: 2400 SourceMeter, measurement-only mode (
Keithley2400) - Simulated: no hardware required; pairs with the bundled DMM simulator (
SimulatedDMM)
Key Concepts
Driver Composition
AnInstroDMM is built from a concrete driver:
Agilent34401Aowns the connection setup and vendor-specific command mapping.InstroDMMowns the category-level workflow: measurements, commands, publishers, the background daemon.
Lifecycle
The typical InstroDMM workflow:- Construct: instantiate the vendor driver and pass it to
InstroDMM. open(): establishes the VISA connection.- Configure measurement: set the measurement function (e.g. DC voltage), and optionally resolution, aperture, and range.
read(): trigger a measurement and get the value.close(): disconnect from hardware.
start() / stop(), but it is an atypical use case for a DMM. See Two ways to get data for more.
Measurement Functions
InstroDMM supports these measurement functions (availability depends on the driver):
- DC Voltage
- AC Voltage
- DC Current
- AC Current
- 2-Wire Resistance
- 4-Wire Resistance
set_measurement_function() before configuring resolution, aperture, range, or calling read().
Creating an InstroDMM Instance
Parameters
name: A name for this DMM instance. Used as a prefix for channel names when publishing.driver: A concreteDMMDriverBaseinstance (e.g.Agilent34401A,Keithley2400) configured with the connection details for that model.publishers: Optional list of publishers to attach.**kwargs: Additional keyword arguments become default tags when using a publisher that supports tags (likeNominalCorePublisher).
Choosing a Driver
Choose the concrete driver that matches the DMM model, then pass the instrument connection settings to that driver. For an Agilent 34401A on RS-232, useAgilent34401A with the VISA resource string and (optionally) a SerialConfig. For a Keithley 2400 SourceMeter, use Keithley2400.
To inspect a VISA instrument’s identity before choosing a driver:
Examples
All measurement methods returnMeasurement objects. This is common amongst all Instrument objects.
Basic Usage
Important Note about PublishersData is published as a direct result of an instrument method being called.For example, when you call
read(), this not only triggers a measurement and returns the value but also causes all attached Publishers to publish the measurement response automatically.Published channels
Every measurement/command call produces a channel keyed under{name}.{descriptor}, where {name} is the constructor argument and {descriptor} is the row below. The read() descriptor depends on the active measurement function. Substitute the lowercased function name (e.g. dc_voltage, ac_voltage, two_wire_resistance). DMM had no v1.0 channel-naming change. legacy_naming is accepted but is a no-op for this category.
Method Reference
set_aperture_seconds is part of the DMM contract but is not implemented by either bundled driver (Agilent 34401A, Keithley 2400). Calling it on those drivers raises NotImplementedError. Use set_aperture_nplc to set integration time on the shipped drivers. See Exceptions for the distinction between NotImplementedError and FeatureNotSupportedError.Custom Driver Development
This section is for developers implementingInstroDMM support for DMMs that aren’t supported out of the box.
Overview
Driver developers subclassDMMDriverBase and own whatever transport their instrument needs. The caller chooses a concrete driver, and that concrete driver exposes connection parameters that make sense for its protocol:
InstroDMM’s vendor-independent API (set_measurement_function, measure_dc_voltage, …) into vendor-specific commands.
Driver Responsibilities
A DMM driver must:- Expose a protocol-native constructor: accept inputs like
visa_resource,host,port, depending on the instrument. - Own transport setup: create and store the transport internally. Do not require users to pass a
VisaDriver, socket client, or other transport object. - Own lifecycle: implement
open()andclose()by opening and closing the underlying transport. - Map commands: translate each abstract method into vendor-specific commands.
- Parse responses: convert instrument responses to the expected Python types (
float).
DMMDriverBase Interface
All DMM drivers subclassDMMDriverBase and implement these abstract methods:
NotImplementedError if not supported):
set_digits(n): Set resolution in digits.set_aperture_seconds(seconds): Set integration time in seconds. (Not implemented by the bundled Agilent 34401A or Keithley 2400 drivers.)- Per-function range setters:
set_dc_voltage_range,set_ac_voltage_range,set_dc_current_range,set_ac_current_range,set_two_wire_resistance_range,set_four_wire_resistance_range. Each takesvalue: float | None(None = auto).InstroDMMdispatches to the right one based on the active measurement function, so the driver never needs to know which function is active. - Per-function NPLC setters:
set_dc_voltage_nplc,set_ac_voltage_nplc,set_dc_current_nplc,set_ac_current_nplc,set_two_wire_resistance_nplc,set_four_wire_resistance_nplc. Same dispatch shape as the range setters. measure_four_wire_resistance(): Measure 4-wire resistance.
InstroDMM’s _measurement_config.function as the single source of truth. The driver never receives or tracks the active function, so the wrong-function-passed-by-mistake class of bug doesn’t exist.
Talking to the Instrument
Concrete drivers should hide transport details behind private attributes. For VISA-backed drivers, create aVisaDriver internally and use it for all I/O:
self._visa.write(command): Send a SCPI command (no response expected).self._visa.query(command): Send a SCPI query and receive the response string.
VisaDriver owns the resource lock. Concurrent write / query calls against the same driver are serialized automatically.
See the VisaDriver guide for the full transport reference, covering configuration, terminators, timeouts, serial settings, and the raw-byte I/O path.
For non-VISA instruments, follow the same shape with the protocol client your driver needs. The important part is that the public constructor describes the instrument connection, while the transport object remains an implementation detail.
Implementation Example: Agilent 34401A Driver
Here is the abridged shape of the Agilent 34401A driver:Using a Custom Driver
For drivers that aren’t shipped in the library, constructInstroDMM with your own driver instance. The driver should accept connection settings directly and create its transport internally:
Summary
Driver development requires careful mapping of vendor-specific behavior to the unifiedInstroDMM interface. Focus on:
- Subclassing
DMMDriverBase - Designing a constructor around natural connection parameters for the instrument
- Hiding transport construction inside the driver
- Implementing all abstract methods on
DMMDriverBase(and optional overrides where supported) - Using the correct vendor protocol or command syntax
- Converting instrument responses to the expected Python types
- Adding a private
_check_errors()helper if your vendor exposes an error queue - Testing with actual hardware to ensure commands work as expected