Skip to content
robin-cachy edited this page Jun 10, 2026 · 5 revisions

CLI

All scripts run directly with Python and use the active workbench by default. Pass --workbench <name> to any script to override.


core/nachoVisa.py — Instrument scanner

Scans USB and LAN for VISA instruments, identifies them, and saves a workbench file.

python core/nachoVisa.py                        # scan USB + LAN, prompt for name
python core/nachoVisa.py --usb-only             # skip LAN scan
python core/nachoVisa.py --host 192.168.1.50    # probe a specific IP
python core/nachoVisa.py --subnet 192.168.1.0/24
python core/nachoVisa.py --save my_lab          # save without prompting
python core/nachoVisa.py --set-active my_lab    # switch active workbench
python core/nachoVisa.py --fix-udev             # write udev rules (Linux)
python core/nachoVisa.py --debug                # verbose output

--fix-udev creates /etc/udev/rules.d/70-usbtmc.rules so PyVISA-py can access USBTMC instruments without root. Run once, then re-plug USB instruments.


core/setWorkbench.py — Apply instrument state

Drives all instruments in the active workbench to a specified state defined in a config JSON file.

GUI equivalent: The Save state / Load state / Reset all bar in the Workbench tab covers the same workflow interactively. Use setWorkbench.py for headless / scripted operation or when the GUI is not running. See Workbench and Instruments#bench-state--save-load-reset.

python core/setWorkbench.py                     # apply workbench_config.json
python core/setWorkbench.py --set foo.json      # apply a specific config file
python core/setWorkbench.py --reset-bench       # safe defaults on all instruments

--reset-bench zeroes outputs and disables all channels without needing a config file. The state files saved by the GUI (workbench_states/*.json) use a compatible format and can be passed to --set.

Config format:

{
  "name": "Lab Ready",
  "hosts": ["192.168.1.100"],
  "instruments": {
    "edu36311a": {
      "outputs": [
        { "channel": 1, "voltage": 5.0, "current_limit": 0.5, "enabled": false }
      ]
    },
    "edu33211a": {
      "channels": [
        { "channel": 1, "function": "SIN", "frequency": 1000,
          "amplitude": 1.0, "amplitude_unit": "VPP", "offset": 0.0, "enabled": false }
      ]
    },
    "scope": { "reset": true }
  }
}

"hosts" lists IP addresses of Ethernet instruments (LAN instruments are not auto-discovered by the @py backend).


scripts/ — Standalone scripts

These run independently without the GUI.

Script What it does
screenshot.py Capture a screenshot from the active workbench scope and save as PNG
acAnalysis.py AC frequency sweep: step a generator through frequencies from a CSV, record Vpp on scope CH1/CH2
dcSweep.py Step one or both PSU channels across a voltage range; log V/I readings at each point
psuInterrupt.py Drive a V1 → interrupt (off or V2) → V3 cycle; sweep interrupt duration and/or voltage across multiple runs
waveformAnalysis.py Live waveform analysis: autoscale, measure freq/Vpp/risetime, save screenshot and CSV

scripts/cgb-US21x-equipment/ contains instrument-specific examples for the Keysight EDU lab kit (EDU33211A AWG, EDU34450A DMM, EDU36311A PSU) and the Korad KA3005P.


Writing your own scripts

open_by_role() returns an Instrument object — the PyVISA resource and its eewBackbone family bundled together. Call .dispatch() to send operations; the instrument already knows which SCPI commands to use.

import pyvisa
from workbench import load_workbench, open_by_role

# Load the active workbench (workbenches/active.json).
# Pass a name to use a different one: load_workbench("portable_rig")
wb = load_workbench()
rm = pyvisa.ResourceManager("@py")

# open_by_role finds the instrument by its "role" field in the workbench JSON
# and looks up its SCPI family from the stored family_id — no IDN query needed.
psu = open_by_role(rm, wb, "psu")
dmm = open_by_role(rm, wb, "dmm")

# .dispatch() sends an eewBackbone operation and returns the query response (or None).
# The instrument already knows its own command set — no family argument needed.
psu.dispatch("set_current_limit", ch=1, value="0.5")  # 500 mA limit
psu.dispatch("output_on", ch=1)

for v in range(1, 6):
    psu.dispatch("set_voltage", ch=1, value=str(v))
    reading = dmm.dispatch("measure_vdc")
    print(f"V_set={v} V   V_meas={float(reading):.4f} V")

psu.dispatch("output_off", ch=1)

The Instrument wrapper is transparent — .write(), .query(), .timeout, and all other PyVISA attributes pass straight through to the underlying resource, so raw SCPI access works the same as before when you need it.

Because all SCPI commands go through eewBackbone.json, this script runs unchanged on any PSU and DMM family that defines set_voltage, set_current_limit, and measure_vdc — swapping instruments only requires updating the workbench file.

Clone this wiki locally