<a id="api-discovery"></a>

# Device Discovery

The device discovery functions allow the application to find Joulescopes
connected to the host.  Most scripts that only support a single Joulescopes
will use:

```default
joulescope.scan_require_one(config='auto')
```

To support multiple Joulescopes, use:

```default
joulescope.scan(config='auto')
```

To select devices, provide device specifications, the same as
pyjoulescope_driver `Driver.device_paths()`:

```default
joulescope.scan_require_one('js320', config='auto')  # the only JS320
joulescope.scan_require_one('8W2A')                  # by serial number
joulescope.scan('u/js220/000415, js320')             # comma-separated
joulescope.scan(['js220', 'js320'])                  # list
```

A specification is a full device path, such as “u/js320/8W2A”, the
backend and model “u/js320”, the model and serial number “js320/8W2A” or
“js320-8W2A”, the model “js320”, or the serial number “8W2A”.  Matching
is case-insensitive.  The joulescope package only returns Joulescope
instruments, so other devices that the driver reports, such as
MiniBitty devices, never match.

Scans exclude devices in bootloader mode, unless you request them with
“bootloader” or a “&” model specification, such as “&js220”.  For
backwards compatibility, “Joulescope” selects all devices.
[`Device.firmware`](https://docs.joulescope.com/en/software/pyjoulescope/api/device.md#joulescope.v1.device.Device.firmware) reports
“app” or “bootloader” for each device.

`scan_require_one()` raises [`joulescope.v1.driver.ScanError`](#joulescope.v1.driver.ScanError)
when zero or multiple devices match.  Its message lists the matching and
available devices.  ScanError is both a ValueError and, for backwards
compatibility, a RuntimeError.

See [`joulescope.v1.device.Device`](https://docs.joulescope.com/en/software/pyjoulescope/api/device.md#joulescope.v1.device.Device).

## scan

### joulescope.scan(specs=None, config=None, name=None) → List[[Device](https://docs.joulescope.com/en/software/pyjoulescope/api/device.md#joulescope.v1.device.Device)]

Scan for connected devices.

* **Parameters:**
  * **specs** – 

    The device specifications, which is one of:
    * None (default) to select all devices.
    * a string containing one or more comma-separated device
      specifications, such as “js320” or “31NB, u/js220/000415”.
    * a list of device specification strings.

    See `pyjoulescope_driver.DevicePath.match()` for the
    specification format.  For backwards compatibility,
    “Joulescope” selects all devices, and “bootloader” selects
    all devices in bootloader mode.
  * **config** – The configuration for the `Device`.
  * **name** – Deprecated alias for specs, for backwards compatibility.
* **Returns:**
  The list of `Device` instances, sorted by name.
  Devices in bootloader mode are only included when requested by
  “bootloader” or a “&” model specification, such as “&js220”.
* **Raises:**
  **TypeError** – If specs has an invalid type.

## scan_require_one

### joulescope.scan_require_one(specs=None, config=None, name=None) → [Device](https://docs.joulescope.com/en/software/pyjoulescope/api/device.md#joulescope.v1.device.Device)

Scan for one and only one device.

* **Parameters:**
  * **specs** – The device specifications.  See [`scan()`](#joulescope.scan).
  * **config** – The configuration for the `Device`.
  * **name** – Deprecated alias for specs.
* **Returns:**
  The `Device` found.
* **Raises:**
  [**ScanError**](#joulescope.v1.driver.ScanError) – If zero or multiple devices match.

## scan_for_changes

### joulescope.scan_for_changes(specs=None, devices=None, config=None, name=None)

Scan for device changes.

* **Parameters:**
  * **specs** – The device specifications.  See [`scan()`](#joulescope.scan).
  * **devices** – The list of existing `Device` instances returned
    by a previous scan.  Pass None or [] if no scan has yet been performed.
  * **config** – The configuration for the `Device` which is one of
    [‘auto’, ‘ignore’, ‘off’].  None is equivalent to ‘auto’.
  * **name** – Deprecated alias for specs.
* **Returns:**
  The tuple of lists (devices_now, devices_added, devices_removed).
  “devices_now” is the list of all currently connected devices.  If the
  device was in “devices”, then return the `Device` instance from
  “devices”.
  “devices_added” is the list of connected devices not in “devices”.
  “devices_removed” is the list of devices in “devices” but not “devices_now”.

## ScanError

### *class* joulescope.v1.driver.ScanError(specs, brand, matches, available)

The scan did not find exactly one device.

This exception is both a
[`pyjoulescope_driver.device_filter.DeviceFilterError`](https://docs.joulescope.com/en/software/joulescope_driver/device_selection.md#pyjoulescope_driver.device_filter.DeviceFilterError)
(a ValueError) and, for backwards compatibility, a RuntimeError.
