Reference

Bundled Plugs

The plugs that ship with OpenHTF — UserInput, ADB and Fastboot over USB (openhtf.plugs.usb), Cambrionix USB hubs, SerialCollectionPlug for serial logging, DeviceWrappingPlug — with install extras, configuration keys and usage.

Last updated · Verified with OpenHTF 1.6.1

OpenHTF is not an instrument library, but a handful of plugs ship in openhtf.plugs. They cover the operator, Android devices over USB, USB hub control and serial port capture. Anything else — SCPI instruments, PLCs, your own DUT protocol — you write yourself, following the instrument guides.

PlugModuleExtraPurpose
UserInputopenhtf.plugs.user_inputOperator prompts (console and Operator UI)
AdbDeviceopenhtf.plugs.usb.adb_deviceusb-plugsAndroid Debug Bridge over USB, no adb binary
FastbootDeviceopenhtf.plugs.usb.fastboot_deviceusb-plugsFastboot protocol over USB
LibUsbHandleopenhtf.plugs.usb.local_usbusb-plugsRaw USB bulk endpoints via libusb1
EtherSyncopenhtf.plugs.cambrionixCambrionix USB hub: map port → device serial, open a handle
SerialCollectionPlugopenhtf.plugs.generic.serial_collectionserial-collection-plugBackground capture of a serial port to a file
DeviceWrappingPlugopenhtf.plugs.device_wrappingBase class that proxies attribute access to a wrapped device object

UserInput

The one plug every production test uses. Covered on the Plugs page (prompt, text_input, timeout_s, image_url) and on Device Under Test (prompt_for_test_start).

USB plugs: ADB and Fastboot

pip install "openhtf[usb-plugs]" pulls in libusb1 and M2Crypto. The plugs speak the ADB and Fastboot wire protocols directly over libusb — no platform adb install, no daemon fighting your test for the device.

android_plug.py
from openhtf.core import base_plugs
from openhtf.plugs.usb import adb_device, local_usb


class AndroidDut(base_plugs.BasePlug):

    def __init__(self):
        # Open the first ADB-interface USB device; filter by serial_number= or port_path= in a fixture.
        handle = local_usb.LibUsbHandle.open(
            interface_class=adb_device.CLASS,
            interface_subclass=adb_device.SUBCLASS,
            interface_protocol=adb_device.PROTOCOL,
        )
        self.adb = adb_device.AdbDevice.connect(handle)

    def shell(self, command: str, timeout_ms: int = 5000) -> str:
        return self.adb.command(command, timeout_ms=timeout_ms)

    def tearDown(self):
        self.adb.close()
main.py
@htf.plug(dut=AndroidDut)
@htf.measures(htf.Measurement("battery_level").in_range(20, 100))
def read_battery(test, dut):
    out = dut.shell("dumpsys battery | grep level")
    test.measurements.battery_level = int(out.split(":")[1])
AdbDevice

command(cmd, raw=False, timeout_ms=None), async_command(...), push(local, remote), pull(remote, local=None), install(apk_path), list(path), reboot(destination=''), remount(), root(), get_serial(), get_system_type(), close(). Authentication uses an RSA key via M2CryptoSigner when the device requires it.

FastbootDevice

connect(usb_handle), get_boot_config(name), set_boot_config(name, value), lock(), close(); flashing helpers live in fastboot_protocol.

LibUsbHandle

open(**filters) / iter_open(**filters) by serial_number, port_path, interface class/subclass/protocol; read(length, timeout_ms), write(data, timeout_ms), port_path, is_closed(), close().

Cambrionix hubs

openhtf.plugs.cambrionix.EtherSync(mac_address) talks to a Cambrionix EtherSync-capable hub and gives get_usb_serial(port_num) and open_usb_handle(port_num), so a fixture can address "the DUT on port 3" instead of a serial number that changes with every unit.

SerialCollectionPlug

Streams everything a serial port emits — a DUT's boot log, a modem trace — to a file while other phases run.

main.py
import openhtf as htf
from openhtf.plugs.generic import serial_collection
from openhtf.util import configuration

CONF = configuration.CONF
CONF.load(serial_collection_port="/dev/ttyUSB0", serial_collection_baud=115200)

@htf.plug(uart=serial_collection.SerialCollectionPlug)
def boot_dut(test, uart):
    uart.start_collection("/tmp/boot.log")
    power_cycle()
    wait_for_prompt()
    uart.stop_collection()
    test.attach_from_file("/tmp/boot.log", name="boot_log")
serial_collection_portconfig key
Default /dev/ttyACM0.
serial_collection_baudconfig key
Default 115200.
start_collection(dest) / stop_collection() / is_collecting()
Collection runs in a thread; a serial error stops it and logs the message.

The constructor uses @CONF.inject_positional_args, so the two keys must be declared/loaded before the plug is instantiated. Importing the module without pyserial installed raises with an explicit hint to install the extra.

DeviceWrappingPlug

A base class for plugs that wrap an existing driver object: set self._device and attribute access falls through to it, with logging of each call. Useful to expose a vendor SDK object as a plug without writing pass-through methods.

main.py
from openhtf.plugs import device_wrapping

class ScopePlug(device_wrapping.DeviceWrappingPlug):
    def __init__(self):
        super().__init__(vendor_sdk.Oscilloscope("192.168.1.20"))   # becomes self._device

# In a phase: scope.set_timebase(1e-3) is forwarded to the SDK object

Writing your own

Everything else is a subclass of BasePlug with __init__, methods and tearDown(). The instrument guides show the three most common transports:

On this page

First-pass yield
0%4.1
Track with TofuPilot