CLI#

Command-line tools for working with instro

instro ships a command-line interface for inspecting and discovering instruments on your bench.

Running the CLI#

The CLI comes with the instro package (see Installation). In a project that has instro installed, run:

uv run instro discover

For regular use, put instro on your PATH instead so you can call it from anywhere:

uv tool install instro
instro discover

Usage#

instro –version#

Prints version information.

instro --version # prints version information

instro discover#

Scans all available VISA resources and serial ports, queries each instrument for its identity, and prints a summary table.

To force a specific VISA backend, pass --backend:

instro discover --backend=@py
instro discover --backend "@ivi"

Note

The @ivi backend finds an available IVI-compliant backend on your system e.g. NI-VISA or Keysight IO. @ivi is more reliable for USB and GPIB instruments. The @py backend (pyvisa-py) is a pure-Python fallback that works without NI-VISA installed but may not detect all instruments.

Output#

Before scanning, the command prints which VISA backend is active (@ivi, or @py when no IVI VISA is installed). On the @py backend it also lists any interfaces the scan cannot cover — for example GPIB: unavailable — gpib_ctypes is installed but could not locate the gpib library (install NI-488.2 or linux-gpib) — so you know when an empty result reflects a missing library rather than an empty bench. These notes are informational; the scan still runs and the command exits 0.

The command groups results into up to three tables.

Recognized devices — instruments with a known driver. The table shows the VISA resource address, instrument category, and the instro driver class to use.

Serial devices — serial ports detected by the OS. These are listed separately because serial instruments require manual configuration; instro discover cannot query them automatically.

Unrecognized devices — instruments that responded to *IDN? but did not match any known driver. The raw IDN response is shown so you can identify the device.

If no devices are found at all, the command prints a single error panel; on the @py backend the panel repeats any unavailable interfaces.

Using a recognized device#

Pass the resource address from the Recognized devices table directly to the driver’s constructor:

from instro.psu.drivers.bk_9115 import BK9115
from instro.psu import InstroPSU

psu = InstroPSU(name="psu", driver=BK9115("USB0::0x15EF::0x0099::INSTR"), num_channels=1)
psu.open()

Unrecognized devices#

If your instrument appears in the Unrecognized devices table, instro does not yet have a driver for it. See Custom instruments for how to author one, or instro-contrib to check for community-contributed drivers.

Discovering programmatically#

instro discover is a thin wrapper around scan_visa_resources, which is also available directly from instro.lib for use in your own scripts:

from instro.lib import scan_visa_resources

result = scan_visa_resources()

for info in result.instruments:
    print(info.resource, info.category, info.driver_name)

for unrecognized in result.unrecognized:
    print(unrecognized.resource, unrecognized.idn)

for error in result.errors:
    print(error.resource, error.hint or error.message)

scan_visa_resources accepts the same backend the CLI’s --backend flag does, plus an optional timeout (seconds per instrument query, default 2) that the CLI doesn’t currently expose. It returns a VisaScanResult with instruments (DiscoveredInstrument), unrecognized (VisaUnrecognizedInstrument), and errors (VisaScanError) — the same data the CLI renders into the tables above.

Each DiscoveredInstrument can build what you need next, so a script never re-derives the driver from the resource string:

from instro.psu import InstroPSU

psu_info = next(i for i in result.instruments if i.category == "psu")

# a ready-to-open driver (VisaConfig with the backend the scan was asked for)
psu = InstroPSU(name="psu", driver=psu_info.make_driver(), num_channels=psu_info.num_channels)

# or the ``driver`` block of a JSON config, for InstroPSU(config=...)
driver_block = psu_info.config_block()

visa_config() returns the VisaConfig on its own, and driver_class() the driver class, when you want to construct the driver yourself.