pytest-embedded-espemu

class pytest_embedded_espemu.app.EspEmuApp(msg_queue: MessageQueue, espemu_image_path: str | None = None, skip_regenerate_image: bool | None = False, encrypt: bool | None = False, keyfile: str | None = None, **kwargs)

Bases: IdfApp

esp-emu App class

image_path

esp-emu flash-able bin path

Type:

str

create_image() → None

Create the image, if it doesn’t exist.

class pytest_embedded_espemu.dut.EspEmuDut(*args, **kwargs)

Bases: Dut

esp-emu dut class

target

target chip type, taken from the app

Type:

str

serial

EspEmuSerial instance

Type:

EspEmuSerial

write(s: AnyStr) → None

Write to the MessageQueue instance

class pytest_embedded_espemu.espemu.EspEmu(espemu_image_path: str | None = None, espemu_prog_path: str | None = None, espemu_cli_args: str | None = None, espemu_extra_args: str | None = None, espemu_efuse_path: str | None = None, espemu_control_port: int | None = None, app: EspEmuApp | None = None, **kwargs)

Bases: DuplicateStdoutPopen

esp-emu class (https://github.com/espressif/esp-emulator)

The emulator runs with UART0 attached to stdio: its output streams straight into the pexpect process and write() feeds the firmware’s UART RX via stdin. No sockets are involved.

DOWNLOAD_MODE_STRAP = '0x02'
EFUSE_IMAGE_SIZE = 336
ESPEMU_PROG_PATH = 'esp-emu'
SOURCE = 'ESPEMU'
SUPPORTED_TARGETS: ClassVar[tuple] = ('esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32s31')
control_command(command: str, timeout: float = 30) → str

Send one command to this emulator’s control channel and return its reply.

execute_efuse_command(command: str) → None

Run an espefuse command against the emulator.

A second emulator instance is started in download mode with its UART on a socket, since the running one is booted into the firmware and a socket carries no reset lines. The instance writes the eFuse image back on exit, and the running emulator then reads it back over the control channel, which resets it – so the burn takes effect on the machine under test as well as on the next start.

Parameters:

command – espefuse command line, e.g. “burn-custom-mac 00:11:22:33:44:55”

classmethod pick_control_port(prog_path: str | None = None) → int | None

A free port for the control channel, or None if this build has none.

A chip reset has no in-band form — on hardware it is a DTR/RTS toggle into EN, and pyserial’s socket:// handler ignores modem control lines — so it goes over esp-emu’s control channel. Older binaries do not have the flag, and passing an unknown one makes them exit, so ask first. Chosen before either the emulator or its serial exists, so both can be handed the same port.

property supports_efuse_load: bool

Whether this build takes efuse-load, which arrived after the channel did.

pytest_embedded_espemu.espemu.send_control_command(port: int | None, command: str, timeout: float = 30) → str

Send one command to an esp-emu control channel and return its reply.