# InstroScope

## class InstroScope( name: str | None = None, driver: ScopeDriverBase | None = None, num_channels: int | None = None, publishers: list[Publisher] | None = None, config: ScopeConfig | dict | Path | str | None = None, autostart: bool = False, **kwargs, )[source]

Bases: [`Instrument`](https://dev.nominal.io/instro/ref/library/instro.lib.instrument.Instrument.md#instro.lib.instrument.Instrument "instro.lib.instrument.Instrument")

Oscilloscope instrument. Tracks scope state locally; call `sync_configuration()` after `open()` to refresh.

Initialize an InstroScope.

Provide either `config` or `driver`/`num_channels` together, not both.

Parameters:
:   - **name**

      Channel-name prefix for published data. Falls back to
      `config.device.name` when `config` is given.
    - **driver**

      Concrete scope driver; owns its own transport:

      ```
      scope = InstroScope(
          "scope",
          driver=Keysight1200X("<visa_resource>"),
          num_channels=4,
      )
      ```
    - **num_channels**

      Analog-input channel count.
    - **publishers**

      Publishers that receive emitted Measurement/Command data.
      Combined with any publishers declared in `config`.
    - **config**

      A `ScopeConfig`, a dict, or a path to a JSON config file. Its
      `channels`, `acquisition`, and `trigger` blocks are applied through
      the public setters on `open()`; each channel’s `measurements` are
      registered as background daemon functions.
    - **autostart**

      When True, open the connection and start background polling.
      Requires `config` with at least one `measurements` entry, since the
      daemon has nothing to poll otherwise.
    - ****kwargs**

      Default tags applied to every emitted Measurement/Command.
      Pass `dataset_rid="<rid>"` to auto-create a NominalCorePublisher
      (uses the on-disk ‘default’ Nominal credential).

Attributes

| [`background_interval`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.background_interval "instro.scope.InstroScope.background_interval") | Seconds between background daemon iterations (0 = no wait). |
| --- | --- |
| [`channel_names`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.channel_names "instro.scope.InstroScope.channel_names") | Return an insertion-ordered snapshot of all published channel names. |

Methods

| [`add_background_daemon_function`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.add_background_daemon_function "instro.scope.InstroScope.add_background_daemon_function") | Append `method` to the daemon's call list. |
| --- | --- |
| [`add_publisher`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.add_publisher "instro.scope.InstroScope.add_publisher") | Register a publisher to receive this instrument's Measurement/Command data. |
| [`close`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.close "instro.scope.InstroScope.close") | Stop the daemon and publishers, then close the underlying driver. |
| [`define_background_daemon`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.define_background_daemon "instro.scope.InstroScope.define_background_daemon") | Replace all daemon functions with a single `method` (called with the given args). |
| [`fetch_waveform`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.fetch_waveform "instro.scope.InstroScope.fetch_waveform") | Fetch the acquired waveform from `channel`. |
| [`force_trigger`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.force_trigger "instro.scope.InstroScope.force_trigger") | Force a trigger event immediately. |
| [`get_acquisition_mode`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_acquisition_mode "instro.scope.InstroScope.get_acquisition_mode") | Query the current acquisition mode (published as a string). |
| [`get_acquisition_state`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_acquisition_state "instro.scope.InstroScope.get_acquisition_state") | Query RUNNING/STOPPED. |
| [`get_average_count`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_average_count "instro.scope.InstroScope.get_average_count") | Query the average count. |
| [`get_channel`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_channel "instro.scope.InstroScope.get_channel") | Return the most recent `length` samples for `channel_name` from the in-memory buffer. |
| [`get_coupling`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_coupling "instro.scope.InstroScope.get_coupling") | Query the input coupling mode on `channel` (published as a string). |
| [`get_horizontal_scale`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_horizontal_scale "instro.scope.InstroScope.get_horizontal_scale") | Query the timebase (seconds/div). |
| [`get_probe_attenuation`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_probe_attenuation "instro.scope.InstroScope.get_probe_attenuation") | Query the probe attenuation ratio on `channel`. |
| [`get_sample_rate`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_sample_rate "instro.scope.InstroScope.get_sample_rate") | Query the current sample rate (Sa/s). |
| [`get_single_channel_value`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_single_channel_value "instro.scope.InstroScope.get_single_channel_value") | Return the most recent sample for `channel_name` from the in-memory buffer. |
| [`get_trigger_status`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_trigger_status "instro.scope.InstroScope.get_trigger_status") | Query the trigger status (published as a string). |
| [`get_vertical_offset`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_vertical_offset "instro.scope.InstroScope.get_vertical_offset") | Query the vertical offset (volts) on `channel`. |
| [`get_vertical_scale`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.get_vertical_scale "instro.scope.InstroScope.get_vertical_scale") | Query the vertical scale (V/div) on `channel`. |
| [`load_settings`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.load_settings "instro.scope.InstroScope.load_settings") | Recall a scope setup. |
| [`measure`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.measure "instro.scope.InstroScope.measure") | Take a built-in measurement on `channel`. |
| [`open`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.open "instro.scope.InstroScope.open") | Open the underlying driver and apply any configured initial state. |
| [`publish`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.publish "instro.scope.InstroScope.publish") | Fan `data` out to every configured publisher; `kwargs` pass through. |
| [`run`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.run "instro.scope.InstroScope.run") | Start continuous acquisition. |
| [`save_screenshot`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.save_screenshot "instro.scope.InstroScope.save_screenshot") | Capture a screenshot and save it. |
| [`save_settings`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.save_settings "instro.scope.InstroScope.save_settings") | Save scope setup. |
| [`set_acquisition_mode`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_acquisition_mode "instro.scope.InstroScope.set_acquisition_mode") | Set the acquisition mode (NORMAL/AVERAGE/HIRES/PEAK_DETECT/ENVELOPE). |
| [`set_average_count`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_average_count "instro.scope.InstroScope.set_average_count") | Set the average count (waveforms averaged) used in AVERAGE acquisition mode. |
| [`set_coupling`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_coupling "instro.scope.InstroScope.set_coupling") | Set AC/DC input coupling on `channel`. |
| [`set_horizontal_scale`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_horizontal_scale "instro.scope.InstroScope.set_horizontal_scale") | Set the timebase (seconds/div). |
| [`set_probe_attenuation`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_probe_attenuation "instro.scope.InstroScope.set_probe_attenuation") | Set the probe attenuation ratio (e.g. 1, 10, 100) on `channel`. |
| [`set_trigger_level`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_trigger_level "instro.scope.InstroScope.set_trigger_level") | Set the trigger level (volts). |
| [`set_trigger_mode`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_trigger_mode "instro.scope.InstroScope.set_trigger_mode") | Set the trigger mode (AUTO/NORMAL). |
| [`set_trigger_slope`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_trigger_slope "instro.scope.InstroScope.set_trigger_slope") | Set the trigger edge slope (RISING/FALLING/EITHER). |
| [`set_trigger_source`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_trigger_source "instro.scope.InstroScope.set_trigger_source") | Set the trigger source to `channel`. |
| [`set_trigger_type`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_trigger_type "instro.scope.InstroScope.set_trigger_type") | Set the trigger type (EDGE, PULSE, …). |
| [`set_vertical_offset`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_vertical_offset "instro.scope.InstroScope.set_vertical_offset") | Set the vertical offset (volts) on `channel`. |
| [`set_vertical_scale`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.set_vertical_scale "instro.scope.InstroScope.set_vertical_scale") | Set the vertical scale (V/div) on `channel`. |
| [`single`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.single "instro.scope.InstroScope.single") | Arm a single-shot acquisition. |
| [`start`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.start "instro.scope.InstroScope.start") | Start the background daemon; warns when nothing is registered to poll. |
| [`stop`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.stop "instro.scope.InstroScope.stop") | Signal the background daemon to stop and join it. |
| [`stop_acquisition`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.stop_acquisition "instro.scope.InstroScope.stop_acquisition") | Stop acquisition; records the acquisition timestamp if one was armed. |
| [`sync_configuration`](https://dev.nominal.io/instro/ref/instruments/instro.scope.InstroScope.md#instro.scope.InstroScope.sync_configuration "instro.scope.InstroScope.sync_configuration") | Bulk-query the instrument and overwrite the tracked `ScopeState` with live state. |

### property background_interval

Seconds between background daemon iterations (0 = no wait).

### open() → None[source]

Open the underlying driver and apply any configured initial state.

### start() → None[source]

Start the background daemon; warns when nothing is registered to poll.

### close() → None[source]

Stop the daemon and publishers, then close the underlying driver.

### sync_configuration() → ScopeState[source]

Bulk-query the instrument and overwrite the tracked `ScopeState` with live state.

Note that trigger source/type/level/slope/mode aren’t bulk-queried — not all scopes expose
every trigger field, so call the per-field getters where supported.

### set_vertical_scale( volts_per_div: float, channel: int, **kwargs, ) → Command[source]

Set the vertical scale (V/div) on `channel`.

### get_vertical_scale( channel: int, **kwargs, ) → Measurement | None[source]

Query the vertical scale (V/div) on `channel`.

### set_vertical_offset( offset: float, channel: int, **kwargs, ) → Command[source]

Set the vertical offset (volts) on `channel`.

### get_vertical_offset( channel: int, **kwargs, ) → Measurement | None[source]

Query the vertical offset (volts) on `channel`.

### set_coupling( coupling: Coupling, channel: int, **kwargs, ) → Command[source]

Set AC/DC input coupling on `channel`.

### get_coupling( channel: int, **kwargs, ) → Measurement[source]

Query the input coupling mode on `channel` (published as a string).

### set_probe_attenuation( factor: float, channel: int, **kwargs, ) → Command[source]

Set the probe attenuation ratio (e.g. 1, 10, 100) on `channel`.

### get_probe_attenuation( channel: int, **kwargs, ) → Measurement | None[source]

Query the probe attenuation ratio on `channel`.

### set_horizontal_scale( seconds_per_div: float, **kwargs, ) → Command[source]

Set the timebase (seconds/div).

### get_horizontal_scale( **kwargs, ) → Measurement | None[source]

Query the timebase (seconds/div).

### get_sample_rate( **kwargs, ) → Measurement | None[source]

Query the current sample rate (Sa/s).

### set_acquisition_mode( mode: AcquisitionMode, **kwargs, ) → Command[source]

Set the acquisition mode (NORMAL/AVERAGE/HIRES/PEAK_DETECT/ENVELOPE).

### get_acquisition_mode( **kwargs, ) → Measurement[source]

Query the current acquisition mode (published as a string).

### set_average_count( count: int, **kwargs, ) → Command[source]

Set the average count (waveforms averaged) used in AVERAGE acquisition mode.

### get_average_count( **kwargs, ) → Measurement | None[source]

Query the average count.

### run(**kwargs) → Command[source]

Start continuous acquisition.

### stop_acquisition(**kwargs) → Command[source]

Stop acquisition; records the acquisition timestamp if one was armed.

### single(**kwargs) → Command[source]

Arm a single-shot acquisition.

### get_acquisition_state( **kwargs, ) → Measurement[source]

Query RUNNING/STOPPED. If STOPPED while armed, records the acquisition timestamp.

### fetch_waveform( channel: int, timeout: float = 5.0, **kwargs, ) → Measurement[source]

Fetch the acquired waveform from `channel`.

Timestamps are ns relative to the trigger point (negative = pre-trigger).
If an acquisition is armed, blocks up to `timeout` seconds for it to
complete; raises `TimeoutError` if it doesn’t.

### measure( measurement_type: ScopeMeasurementType, channel: int = 1, timeout: float = 5.0, **kwargs, ) → Measurement | None[source]

Take a built-in measurement on `channel`.

Timestamps default to the last recorded acquisition time (falls back to
`time.time_ns()` if none). If an acquisition is armed, blocks up to
`timeout` seconds for it to complete; raises `TimeoutError` if it doesn’t.

### set_trigger_source( channel: int, **kwargs, ) → Command[source]

Set the trigger source to `channel`.

### set_trigger_type( trigger_type: TriggerType, **kwargs, ) → Command[source]

Set the trigger type (EDGE, PULSE, …).

### set_trigger_level( level: float, **kwargs, ) → Command[source]

Set the trigger level (volts).

### set_trigger_slope( slope: TriggerSlope, **kwargs, ) → Command[source]

Set the trigger edge slope (RISING/FALLING/EITHER).

### set_trigger_mode( mode: TriggerMode, **kwargs, ) → Command[source]

Set the trigger mode (AUTO/NORMAL).

### force_trigger(**kwargs) → Command[source]

Force a trigger event immediately.

### get_trigger_status( **kwargs, ) → Measurement[source]

Query the trigger status (published as a string).

### save_screenshot( filepath: str, to_instrument: bool = False, **kwargs, ) → Command[source]

Capture a screenshot and save it. `to_instrument=True` writes to the scope’s filesystem; otherwise to the host.

### save_settings( name: str, to_instrument: bool = False, **kwargs, ) → Command[source]

Save scope setup. `to_instrument=True` writes to the scope’s filesystem; otherwise to the host.

### load_settings( name: str, from_instrument: bool = False, **kwargs, ) → Command[source]

Recall a scope setup. `from_instrument=True` reads from the scope’s filesystem; otherwise from the host.

Invalidates the tracked `ScopeState` since instrument state changed externally;
call `sync_configuration()` to refresh.

### add_background_daemon_function( method: Callable, *args, **kwargs, )

Append `method` to the daemon’s call list. Use `define_background_daemon` to replace instead.

### add_publisher( publisher: Publisher, )

Register a publisher to receive this instrument’s Measurement/Command data.

### property channel_names: tuple[str, ...]

Return an insertion-ordered snapshot of all published channel names.

Names are complete after one full daemon iteration: {name}.loop_time publishes
every iteration, so call get_channel(“loop_time”, wait_for_new_samples=True)
then read channel_names to ensure the complete set has arrived.

Raises:
:   [**RuntimeError**](https://docs.python.org/3/builtins/exceptions.html#RuntimeError "(in Python v3.15)") – No background buffer; `start()` was not called.

### define_background_daemon( method: Callable, *args, **kwargs, )

Replace all daemon functions with a single `method` (called with the given args).

### get_channel( channel_name: str, length: int = 1, wait_for_new_samples: bool = False, timeout: float = 10.0, ) → Measurement

Return the most recent `length` samples for `channel_name` from the in-memory buffer.

If the channel does not exist yet, or no sample is available, the code will always block until `timeout` expires.

Parameters:
:   - **channel_name**

      Name of the channel to retrieve.
    - **length**

      Number of trailing samples to return.
    - **wait_for_new_samples**

      Block until at least `length` new values arrive.
    - **timeout**

      Seconds to wait when insufficient data exists or `wait_for_new_samples=True`.

Raises:
:   - [**RuntimeError**](https://docs.python.org/3/builtins/exceptions.html#RuntimeError "(in Python v3.15)") – No background buffer; `start()` was not called.
    - [**ChannelNotFoundError**](https://dev.nominal.io/instro/ref/library/instro.lib.publishers.channel_buffer.ChannelNotFoundError.md#instro.lib.publishers.channel_buffer.ChannelNotFoundError "instro.lib.publishers.channel_buffer.ChannelNotFoundError") – channel had no values and no data appeared before `timeout`.
      `wait_for_new_samples=True` and channel did not appear within `timeout`.
    - [**ChannelValueTimeoutError**](https://dev.nominal.io/instro/ref/library/instro.lib.publishers.channel_buffer.ChannelValueTimeoutError.md#instro.lib.publishers.channel_buffer.ChannelValueTimeoutError "instro.lib.publishers.channel_buffer.ChannelValueTimeoutError") – `wait_for_new_samples=True` and values did not arrive within `timeout`.

### get_single_channel_value( channel_name: str, ) → float | str | None

Return the most recent sample for `channel_name` from the in-memory buffer.

This will not wait, if data is not available then `None` is returned.

Parameters:
:   **channel_name**

    Name of the channel to retrieve.

Raises:
:   [**RuntimeError**](https://docs.python.org/3/builtins/exceptions.html#RuntimeError "(in Python v3.15)") – No background buffer; `start()` was not called.

### publish( data: Measurement | Command, **kwargs, )

Fan `data` out to every configured publisher; `kwargs` pass through.

### stop()

Signal the background daemon to stop and join it. No-op if not running.
