From 22be547e47431570c9ea4389184e730970503d44 Mon Sep 17 00:00:00 2001 From: Kai Chappell Date: Fri, 26 Sep 2025 17:56:36 +0000 Subject: [PATCH] Add instrument CLI commands --- src/py_dvt_ate/app/cli.py | 34 ++++++++++++ src/py_dvt_ate/app/instrument_commands.py | 68 +++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/py_dvt_ate/app/instrument_commands.py diff --git a/src/py_dvt_ate/app/cli.py b/src/py_dvt_ate/app/cli.py index 0b5d16a..e5f25fd 100644 --- a/src/py_dvt_ate/app/cli.py +++ b/src/py_dvt_ate/app/cli.py @@ -125,5 +125,39 @@ def run_test_cmd( ) +@app.command(name="query") +def query_cmd( + instrument: Annotated[ + str, + typer.Argument(help="Instrument to query (chamber, psu, or dmm)."), + ], + command: Annotated[ + str, + typer.Argument(help="SCPI command to send (e.g., *IDN?, TEMP:SETPOINT?)."), + ], + config_file: Annotated[ + str | None, + typer.Option("--config", "-c", help="Path to configuration YAML file."), + ] = None, +) -> None: + """Send a SCPI command to an instrument and print the response. + + Useful for debugging and manual instrument control. Connect to + instruments based on configuration and send raw SCPI commands. + + Examples: + py-dvt-ate query chamber "*IDN?" + py-dvt-ate query psu "VOLT? 1" + py-dvt-ate query dmm "MEAS:VOLT:DC?" + """ + from py_dvt_ate.app.instrument_commands import query_instrument + + query_instrument( + instrument=instrument, + command=command, + config_file=config_file, + ) + + if __name__ == "__main__": app() diff --git a/src/py_dvt_ate/app/instrument_commands.py b/src/py_dvt_ate/app/instrument_commands.py new file mode 100644 index 0000000..1abd7b8 --- /dev/null +++ b/src/py_dvt_ate/app/instrument_commands.py @@ -0,0 +1,68 @@ +"""Instrument query commands for CLI.""" + +import typer + +from py_dvt_ate.app.config import load_config +from py_dvt_ate.instruments.factory import InstrumentConfig, InstrumentFactory + + +def query_instrument( + instrument: str, + command: str, + config_file: str | None = None, +) -> None: + """Send a SCPI command to an instrument and print the response. + + Args: + instrument: Instrument to query (chamber, psu, or dmm). + command: SCPI command to send. + config_file: Path to configuration YAML file. + """ + # Load configuration + config_path = config_file or "config/default.yaml" + try: + config = load_config(config_path) + except FileNotFoundError as err: + typer.echo(f"Error: Configuration file not found: {config_path}", err=True) + raise typer.Exit(code=1) from err + except Exception as e: + typer.echo(f"Error loading configuration: {e}", err=True) + raise typer.Exit(code=1) from e + + # Create instruments + try: + # Convert AppConfig to InstrumentConfig + inst_config = InstrumentConfig( + backend=config.instruments.backend, + simulator_host=config.instruments.simulator.host, + chamber_port=config.instruments.simulator.thermal_chamber_port, + psu_port=config.instruments.simulator.power_supply_port, + dmm_port=config.instruments.simulator.multimeter_port, + chamber_visa=config.instruments.pyvisa.thermal_chamber, + psu_visa=config.instruments.pyvisa.power_supply, + dmm_visa=config.instruments.pyvisa.multimeter, + ) + instruments = InstrumentFactory.create(inst_config) + except Exception as e: + typer.echo(f"Error connecting to instruments: {e}", err=True) + raise typer.Exit(code=1) from e + + # Send command to the specified instrument + try: + # Access the transport layer to send raw commands + if instrument == "chamber": + response = instruments.chamber._transport.query(command) # type: ignore[attr-defined] + elif instrument == "psu": + response = instruments.psu._transport.query(command) # type: ignore[attr-defined] + elif instrument == "dmm": + response = instruments.dmm._transport.query(command) # type: ignore[attr-defined] + else: + typer.echo(f"Error: Unknown instrument '{instrument}'", err=True) + typer.echo("Valid instruments: chamber, psu, dmm", err=True) + raise typer.Exit(code=1) + + if response: + typer.echo(response) + except Exception as e: + typer.echo(f"Error sending command: {e}", err=True) + raise typer.Exit(code=1) from e