breadboard
13 · Every part

Component reference

Generated from the same part documentation the app ships: footprints, behavior notes, pin meanings, and sharp edges, by category.

This reference also lives inside the app (Help → Component reference), where each part links to the examples that use it and can be placed with one click.

Arduino

Arduino Nano
arduinonano

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Arduino Nano (classic V3, real emulated ATmega328P) with props.boardLayout="physical-v1": 15 columns, 30 contacts and a 15.24 mm row gap. Place free or straddle the breadboard channel (e.g. anchor row c, opposite row g). USB is on the RIGHT. Bottom row: d1(TX1), d0(RX0), reset, gnd, d2-d12. Top row: vin, gnd2, reset2, 5v, a7, a6, a5, a4, a3, a2, a1, a0, aref, 3v3, d13. Documents without boardLayout retain the original e/f footprint. a4/a5 are REAL GPIOs that carry I²C (SDA=A4, SCL=A5 — wire I²C devices there; no dedicated sda/scl pins). A6/A7 are ADC-only pads (channels 6/7): perfect for analog sensors, but they have NO digital function at all — no pinMode, no digitalRead, no pull-up. Both reset pins are one net; pulling either low resets the board. Hardware SPI = d13(SCK)/d11(MOSI)/d12(MISO); LED "L" mirrors d13. With an explicit boolean props.usbPowerConnected, VIN feeds the onboard regulator: use at least 6.5 V (7–12 V typical). A 5 V supply goes to 5v. Without that boolean, saved boards retain the legacy VIN-to-5v tie: use 5 V on VIN or 5v; 3v3 is the USB-bridge LDO output (weak, ~150 mA class). props.firmware = "example:blink" | the other 328P example ids | Intel HEX compiled for arduino:avr:nano (cpu=atmega328). Modeled: cycle-exact CPU with 2 KB SRAM, timers/PWM, ADC (all 8 channels), interrupts, UART TX+RX (serial monitor typing reaches Serial.read), EEPROM (persists across resets within a session), watchdog reset, and physical pin coupling (drive strength, pull-ups). Transaction-level: SPI and I²C move bytes/ACKs, not wire-level bits on the pins. Not modeled: bootloader and fuses (code runs straight from reset), the USB bridge as a device, USART pin waveforms.

d1d0resetgndd2d3d4d5d6d7d8d9d10d11d12vingnd2reset25va7a6a5a4a3a2a1a0aref3v3d13
Arduino Uno R3
arduinouno

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Classic Arduino Uno R3 (real emulated ATmega328P). New placements use props.boardLayout="compact-v1", with artwork and contacts at two-thirds workbench scale. The reference PCB is 68.58 x 53.34 mm, with 48.26 mm header-row spacing and a 4.064 mm D8-D7 gap. Saved physical-v1 boards retain full scale. sda-header/scl-header duplicate sda/scl electrically. NC and ICSP are artwork only. Documents without boardLayout retain the original footprint. R3 header in silkscreen order: d0-d13, a0-a3 plus sda(A4)/scl(A5) (all six are real ADC inputs for analogRead), aref, reset (pull low to reset the board), ioref, gnd/gnd2/gnd3, vin/5v/3v3. With an explicit boolean props.usbPowerConnected, VIN feeds the onboard regulator: use at least 6.5 V (7–12 V typical). A 5 V supply goes to 5v. Without that boolean, saved boards retain the legacy VIN-to-5v tie: use 5 V on VIN or 5v. props.firmware = "example:blink" | "example:serial-hello" | Intel HEX from the Arduino IDE (Sketch → Export Compiled Binary). Best placed free on the bench and wired pin-to-pin. Modeled: cycle-exact CPU with 2 KB SRAM, timers/PWM, ADC, interrupts, UART TX+RX (serial monitor typing reaches Serial.read), EEPROM (persists across resets within a session), watchdog reset, and physical pin coupling (drive strength, pull-ups). Transaction-level: SPI and I²C move bytes/ACKs, not wire-level bits on the pins. Not modeled: bootloader and fuses (code runs straight from reset).

arefgnd3d13d12d11d10d9d8d7d6d5d4d3d2d1d0iorefreset3v35vgndgnd2vina0a1a2a3sdasclscl-headersda-header
Arduino Uno R4
unor4wifi

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Arduino Uno R4 board. New placements use props.boardLayout="compact-v1" with shield proportions at two-thirds workbench scale; saved physical-v1 boards retain full scale; sda-header/scl-header duplicate sda/scl electrically. Qwiic remains a separate bus. Documents without boardLayout retain the original footprint. The board has a real emulated RA4M1 Cortex-M4 at 48 MHz and solved 5 V header pads. Power through 5v/gnd or VIN. D0-D13 and A0-A5 follow the physical board; A4/A5 are sda/scl. Wire uses those shield pins; independent Wire1 uses qwiic-sda/qwiic-scl with qwiic-gnd and the real qwiic-3v3 rail. The original shield anchors are unchanged. Firmware is explicit: empty means parked; validated raw BIN, Intel HEX and ARM ELF load at application address 0x4000. The gallery includes genuine official-core Blink, a 12×8 matrix heart and ArduinoGraphics scrolling text, pot-controlled ADC14/DAC12 sine and dual OLED patterns. The matrix is driven by guest timer interrupts and pin multiplexing. A0 is the DAC output, with real load, settling and output limits. SPI0 uses D11 MOSI, D12 MISO, D13 SCK and GPIO D10 chip select; Serial1 uses D1 TX and D0 RX through solved nets. SCI9 is the independent console. The official SoftwareSerial library runs on this board only (no other board supports SoftwareSerial): it drives TX on any header pin and samples RX through the real RA4M1 DMA controller, GPT timers and event links, so RX must be a pin with an external interrupt: D0, D1, D2, D3, D6, D8, D11, D12 or A1-A5 (RX on D4, D5, D7, D9, D10, D13 or A0 stops the board in begin() with an explicit unsupported pin-interrupt error, as does enabling one interrupt number on two pins, e.g. RX on A4 while attachInterrupt uses D2). It exchanges bytes with another board's Serial1 or any real UART waveform; the unmodified SerialEcho example (115200 8E2), a 9600 8N1 echo and RX on every interrupt-capable pin, with end() and begin() again, are tested. The library itself transmits data bit 7 in place of the parity bit and ignores receive parity/framing errors; the emulator reproduces that rather than correcting it. The virtual S3 bridge executes official WiFiS3 serial commands for scan, station association, DHCP/DNS, local TCP/UDP and deterministic NTP. Hostname PING uses the existing virtual DNS/ICMP path, with a minimum 1 ms RTT policy after a real echo reply; this is not internet ping. UNO R4 stations and guest access points answer IPv4 unicast ICMP echo at their own IP over the shared virtual air. External numeric destinations (including the stock WiFiUdpNtpClient and WiFiPing targets) are refused, and WiFiClient FLUSH remains unsupported. The two-board Wi-Fi gallery example creates a real guest-controlled WPA2 access point and exchanges HTTP that changes the server’s D13 LED; its Inspector reports the AP address and connected station. Official SoftwareATSE calls use real P-256/SHA-256 math and replayable virtual key/slot storage; this is not tamper-resistant hardware. Current firmware acceptance also covers external IRQ, tone and a patched public Servo path. Public RTC and EEPROM work with the documented compiler compatibility patches, source-clock timing and bus waits; the original unpatched images remain explicit failures. RTC/AGT standby and qualified VRTC backup retention have real-firmware acceptance. The independent backup supply connects to vrtc/vrtc-gnd, including the physical GND/VRTC contacts; OFF remains decorative. For protected peer/server traffic use the guest-controlled WPA2 access point; the shared private virtual BSS supports open peer relay. Core TinyUSB CDC/HID reports are visible in the Inspector without host keyboard or mouse input. Board power, reset and checkpoints preserve real peripheral state. SPI/IIC use timed byte transactions, not analyzer-accurate wire waveforms. Completion gates remain open for CAN, OPAMP, BLE, OTA, TLS, standalone Keyboard/Mouse libraries and physical flashing; do not advertise them as completed. No physical flash action is enabled.

arefgnd3d13d12d11d10d9d8d7d6d5d4d3d2d1d0iorefreset3v35vgndgnd2vina0a1a2a3sdasclqwiic-gndqwiic-3v3qwiic-sdaqwiic-sclvrtc-gndvrtcscl-headersda-header
Arduino Mega 2560
arduinomega

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Arduino Mega 2560 (real emulated ATmega2560): the big AVR board — 54 digital pins (d0-d53), 16 analog inputs (a0-a15, all real ADC channels incl. a8-a15 via the MUX5 bank), 4 hardware serial ports, 6 timers with 15 PWM pins (d2-d13, d44-d46), 8 KB SRAM, 256 KB flash, 4 KB EEPROM. New placements use props.boardLayout="compact-v1", scaling the 101.60 x 53.34 mm reference footprint to two-thirds workbench size. Saved physical-v1 boards retain full scale; sda-header/scl-header are copper aliases of d20/d21. NC and ICSP are artwork only. Documents without boardLayout retain the original footprint. Full header in silkscreen order: top d0-d21 (+aref/gnd3), bottom power (ioref/reset/3v3/5v/gnd/gnd2/vin) + a0-a15, right edge the 2x18 double-row header d22-d53 with 5v2/5v3/gnd4/gnd5 end pins. With an explicit boolean props.usbPowerConnected, VIN feeds the onboard regulator: use at least 6.5 V (7–12 V typical). A 5 V supply goes to 5v. Without that boolean, saved boards retain the legacy VIN-to-5v tie: use 5 V on VIN or 5v. I2C is d20(SDA)/d21(SCL) — REAL digital pins, no dedicated sda/scl nodes; hardware SPI is d50(MISO)/d51(MOSI)/d52(SCK)/d53(SS). props.firmware = "example:mega-blink" | "example:mega-serial-hello" | Intel HEX compiled for arduino:avr:mega (256 KB images with extended-address records load fine). Onboard "L" LED mirrors d13 (PB7 on this chip). Modeled: cycle-exact CPU with the faithful 22-bit PC, timers 0-5 (compare units A/B/C), 16-channel ADC, INT0-INT7 + pin-change interrupts, UART0 TX+RX to the serial monitor, EEPROM, watchdog, physical pin coupling. Serial1 (d19/d18), Serial2 (d17/d16) and Serial3 (d15/d14) are fully modeled at the register/interrupt level so code using them runs correctly, but only Serial (USART0) reaches the serial monitor; USART pin-level waveforms are not modeled. Not modeled: bootloader/fuses, the XMEM external-memory interface.

arefgnd3d13d12d11d10d9d8d7d6d5d4d3d2d1d0d14d15d16d17d18d19d20d21iorefreset3v35vgndgnd2vina0a1a2a3a4a5a6a7a8a9a10a11a12a13a14a155v25v3d22d23d24d25d26d27d28d29d30d31d32d33d34d35d36d37d38d39d40d41d42d43d44d45d46d47d48d49d50d51d52d53gnd4gnd5scl-headersda-header
ATmega328P module
atmega328p

SUPERSEDED — prefer the arduinonano part for new projects; this one stays valid forever so existing circuits keep loading. Bare ATmega328P module straddling the channel (anchor row e) — a 22-pin barebones breakout, not the full Arduino Nano (that is the arduinonano part, which has the complete 30-pin header incl. the ADC-only A6/A7). Pins d0-d13, a0-a3 (real ADC inputs for analogRead), sda(A4)/scl(A5). props.firmware = "example:<id>" (see FIRMWARE PROGRAMS below) or a full Intel HEX string. Wire vcc and gnd. Modeled: cycle-exact ATmega328P CPU with 2 KB SRAM, timers/PWM, ADC, interrupts, UART TX+RX (serial monitor typing reaches Serial.read), EEPROM (persists across resets within a session), watchdog reset, and physical pin coupling (drive strength, pull-ups). Transaction-level: SPI and I²C move bytes/ACKs, not wire-level bits on the pins. Not modeled: bootloader and fuses (code runs straight from reset).

gndvccd2d3d4d5d6d7d13d12d11d10d9d8a1a0sdascld0d1a2a3

Raspberry Pi

Pi Pico
pipico

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Raspberry Pi Pico (real emulated RP2040, 3.3 V logic!) straddling the channel, anchor row e, 11 columns. Wire gnd + vsys (5 V in); the 3v3 pin is a real 3.3 V output. props.firmware = "example:<pico id>" or "uf2:<base64>". A UF2 boots through the real Raspberry Pi RP2040 B1 boot ROM, which Breadboard serves as a separate GPLv2 file with its notices and complete source under /firmware/rp2040-bootrom/. The hosted Code tab builds one main.c with the fixed pico-sdk 2.3.0 C profile and boots the served UF2; Arduino libraries and user CMake flags do not apply, and this profile is plain-Pico only (not Pico W). Measured alternative firmware: CircuitPython 10.2.1 and 9.2.8 both reach their interactive Python prompt over USB serial, basic digital/analog APIs, and their CIRCUITPY FAT volume. Once boot.py gives Python write ownership, guest writes persist across resets within a session; the golden pre-provisions that file through a test-only FAT seam. Host-side USB mass storage is not modeled, so a stock upload cannot install boot.py in the workbench and stays read-only to Python. A Rust rp2040-hal 0.12.0 UF2 boots and toggles GPIO; this does not imply every hardware abstraction layer peripheral works. Fixed transaction pins: UART0 TX/RX = GP0/GP1 and UART1 TX/RX = GP20/GP21 (TX from either reaches the serial monitor; typed serial reaches UART0 and USB CDC); I²C0 SDA/SCL = GP4/GP5 and I²C1 = GP6/GP7; SPI0 SCK/MOSI/MISO = GP18/GP19/GP16 and SPI1 = GP26/GP27/GP28. Stock Pico MicroPython already defaults I2C(1) to SDA=GP6/SCL=GP7, but bare UART(1) defaults to GP4/GP5 and bare SPI(1) to GP10/GP11/GP8, so those two miss the modeled bridges: use UART(1, tx=Pin(20), rx=Pin(21)) and SPI(1, sck=Pin(26), mosi=Pin(27), miso=Pin(28)) explicitly. Modeled: one Cortex-M0+ execution core, GPIO/PIO/PWM/ADC, DMA/timers, USB CDC, UART0/UART1 TX, deterministic RTC calendar alarms with IRQ25, watchdog whole-board reset (including a fresh CDC wake), and ROM/SSI flash erase/program with session-persistent guest filesystems. I²C0/1 and SPI0/1 use the existing byte/ACK transaction seams. The QSPI pad bank starts at its datasheet reset values. The drawn BOOTSEL is a momentary button: click and hold it to pull QSPI_SS low; releasing restores the default pulled-up level. QSPI SCLK and SD0..3 do not expose pin-level flash waveforms; flash traffic uses the transaction-level SSI FIFO seam. Not modeled: the second RP2040 CPU core, dynamic pin-mux routing for those transaction seams, pin-level I²C/SPI/UART waveforms, and host-side USB classes beyond CDC.

gndvsysgp0gp1gp2gp3gp4gp5gp6gp7gp83v3gp16gp17gp18gp19gp20gp21gp22gp26gp27gp28
Pi Pico W
pipicow

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Raspberry Pi Pico W (real emulated RP2040 + a modelled CYW43439 Wi-Fi chip, 3.3 V logic) straddling the channel, anchor row e, 11 columns — the same 22-pin footprint as pipico (the radio hangs off internal GPIOs). Wire gnd + vsys (5 V in); the 3v3 pin is a real 3.3 V output. NO bundled firmware: props.firmware is either a user-uploaded "uf2:<base64>" image (Inspector upload — use the official RPI_PICO_W MicroPython build from micropython.org) or empty, and an empty/omitted firmware leaves the board idle. The UF2 boots through the same separately served RP2040 B1 boot ROM as pipico. AI-authored documents therefore cannot ship a runnable Pico W — pick an ESP32 board for script projects and leave this part to users with their own UF2. With the MicroPython UF2 uploaded the serial monitor is a live Python REPL and network.WLAN works for real on the same virtual air as the ESP32 boards: scan, WPA2-PSK join, DHCP, sockets, board-to-board — networks come from props.wifi ("ssid:channel:rssi[:password]" comma list, editable live in the Inspector). The Pico W is station-only: `network.WLAN(network.AP_IF)` returns but does not create a visible access point, so use `props.wifi` virtual networks for board-to-board Wi-Fi. The onboard LED sits on the radio chip's GPIO0 — machine.Pin("LED") drives it, no RP2040 pin involved. Bluetooth LE works too: the same CYW43439 is an HCI LE controller behind stock MicroPython's BTstack host, so the `bluetooth` module (and aioble) advertises, scans, connects and carries GATT in BOTH roles on the same shared BLE air as the ESP32-C6 — interop both directions. BLE pairing/bonding works too — legacy Just-Works pairing encrypts the link (both hosts fire _IRQ_ENCRYPTION_UPDATE with a 16-byte key), bonds persist via the secret store, and it interoperates with the ESP32-C6 in both directions — BUT it needs a custom MicroPython build: the official RPI_PICO_W v1.25.0 build ships no gap_pair at all (AttributeError — modbluetooth is compiled without pairing/bonding), so with the stock UF2 gap_pair does not exist. Notify payloads clip at the default 20-byte ATT MTU. Its RP2040 side has the same fixed UART0/1, I²C0/1 and SPI0/1 transaction bridges, RTC alarms, and coherent watchdog reset as the plain Pico. Stock RPI_PICO_W MicroPython already puts I2C(1) on GP6/GP7, but callers must pass UART(1, tx=Pin(20), rx=Pin(21)) and SPI(1, sck=Pin(26), mosi=Pin(27), miso=Pin(28)) explicitly to reach the modeled UART1/SPI1 bridges. Guest flash writes use the ROM/SSI path and survive Restart from power-on, brown-outs, and watchdog resets within a session; a firmware upload is a genuine re-flash and starts clean. Watchdog reset also rebuilds the CYW43439 and re-arms the app's CDC wake nudge. The QSPI pad bank starts at its datasheet reset values. The drawn BOOTSEL is a momentary button: click and hold it to pull QSPI_SS low; releasing restores the default pulled-up level. QSPI SCLK and SD0..3 do not expose pin-level flash waveforms; flash traffic uses the transaction-level SSI FIFO seam. Not modeled: the second RP2040 CPU core, dynamic pin-mux routing for the transaction seams, pin-level I²C/SPI/UART waveforms, and host-side USB classes beyond CDC.

gndvsysgp0gp1gp2gp3gp4gp5gp6gp7gp83v3gp16gp17gp18gp19gp20gp21gp22gp26gp27gp28
P2
Pi Pico 2
pipico2

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Raspberry Pi Pico 2 (real emulated RP2350, 3.3 V logic) straddling the channel, anchor row e, 11 columns — pin-for-pin the same 22-pin footprint as pipico, because it is the same board with a different chip. Breadboard runs both of the RP2350's cores in whichever mode the image selects — the default Arm build on two Cortex-M33 cores (with the GPIO, double-precision and redundancy coprocessors), or the RISC-V CPU mode build on two Hazard3 cores — in an in-house emulator, not a JS one. The loader validates every UF2 block and the complete executable stream before boot, and rejects truncated, malformed, RP2040, or RP2350 Arm Non-secure images with an RP2350-specific diagnostic. Wire gnd + vsys (5 V in); the 3v3 pin is a real 3.3 V output. There is NO default firmware: props.firmware is normally either a user-uploaded "uf2:<base64>" image (Inspector upload — either official RPI_PICO2 build from micropython.org boots: the default Arm download or the RISC-V CPU mode variant) or empty, and an empty/omitted firmware leaves the board idle. The hosted Code tab also builds one main.c with the fixed pico-sdk 2.3.0 C profile for the Pico 2 (RP2350 Arm-S, hard-float, double precision on the double coprocessor, printf %f) and boots the served Arm-S UF2 here; its UART0 stdio (GP0/GP1) reaches the serial monitor. Arduino libraries and user CMake flags do not apply, and the profile is plain-Pico 2 only (not Pico 2 W). The built-in `pico2-i2c-sensor` example/tutorial alone pins a provenance-recorded official v1.29.0 asset; firmware resolution never falls back to it. AI-authored documents must not reference that content-only asset or otherwise claim a runnable Pico 2 — pick an ESP32 board for generated script projects and leave this part to users with their own UF2. With a MicroPython UF2 uploaded the serial monitor is a live Python REPL over emulated USB CDC, and machine.Pin and machine.ADC work against the real solved circuit: ADC(26)/ADC(27)/ADC(28) read the actual net voltages, the onboard LED is machine.Pin(25), IO_BANK0 overrides/status and level/edge interrupts are live, and GPIO transitions reach WS2812/SPI-display taps plus the wired-bus analyzer at their exact emulated cycles. All three RP2350 PIO version-1 blocks (PIO0/1/2, four state machines each) run autonomously on the simulation clock and couple to the solved GPIO nets through live FUNCSEL and GPIOBASE mapping. Stock MicroPython `rp2.StateMachine` programs are fresh-boot verified with deterministic FIFO-driven output and exact cycle-stamped edges. The RP2350 additions — IN_COUNT masking, WAIT JMPPIN, cross-block/relative IRQ indexing, MOV PINDIRS and random-access RX FIFO put/get — are modeled too. All 16 DMA channels and the four pacing timers are live through stock MicroPython `rp2.DMA`/`rp2.DMATimer`: widths, address modes, rings, chaining, interrupts, abort, byte swap and transfer progress use the real RP2350 memory/MMIO bus paths. DREQ pacing is connected to every modeled PIO FIFO, both SPI, UART and I²C controllers, all 12 PWM wraps, and the ADC FIFO; peripheral DMA reads and writes retain the same destructive FIFO and timed side effects as CPU accesses. The hardware watchdog counts from TICK_WATCHDOG and performs a coherent whole-board reset; flash and watchdog scratch survive it, the reset reason is retained, and the host gets a reboot event so CDC can re-enumerate. Each component id also produces a stable, distinct machine.unique_id(). UART0/1 TX and RX follow every exposed RP2350A GPIO FUNCSEL=2/11 route through the live pad and override path at baud-rate wire time. Solved-wire receive uses the hardware 16x clock and three-sample majority vote; 5–8 data bits, parity, one/two stop bits, break, inversion, FIFO errors/timeouts, loopback and CTS/RTS flow control are modeled. Multiple selected RX/CTS inputs use the RP2350 logical-OR rule. Both UARTs remain independently reset/clocked. UART0 and UART1 TX both also reach the serial monitor, exactly as on the Pico (each frame once its stop bit has left the shifter, so pico-sdk UART stdio and any UART logging are visible), while the frame still crosses the wired pins unchanged; diagnostic loopback is not shown. Typed serial reaches USB CDC and paced UART0 RX for console compatibility, and never UART1. Hardware I²C0/1 follows the live RP2350 FUNCSEL=3 mux, validating SDA and SCL independently for the same controller. The simplest proven stock-MicroPython route is I2C(0, sda=Pin(4), scl=Pin(5)); valid exposed alternate pairs work too. Scan, read, write, repeated START, NACK and FIFO/interrupt state reach circuit I²C devices at controller wire time. Ordinary controller traffic exposes aggregate SCL low/release ownership plus logical byte/ACK behavior, not SDA address/data edges; the stock scanner is the one path whose real SIO edges and SDA ACK-low sample are visible. Generic SoftI2C, missing-pull-up/stuck-low sensing, external clock stretching, arbitration and per-bit analyzer/scope waveforms are not modeled. If I2C0 and I2C1 are wired onto one already-owned bus, the second controller errors explicitly until STOP. Hardware SPI0/1 follows the live RP2350 FUNCSEL=1 mux for SCK, TX/MOSI, RX/MISO and hardware CS. Stock MicroPython `machine.SPI` is verified through the real PL022 FIFOs and the circuit microSD model: SPI0 defaults to SCK=GP18/MOSI=GP19/MISO=GP16, an alternate exposed SPI0 route is GP6/GP7/GP4, and the exposed SPI1 route is GP26/GP27/GP28 (pass those SPI1 pins explicitly). CS may be a GPIO driven by the script; hardware-controlled CS also follows FUNCSEL, including its trailing serial-clock period and CPHA-dependent interword pulse/hold behavior. Modes 0–3, MSB-first data, reset/clock gating, FIFO status/interrupts and divider wire time are modeled. The circuit seam is deliberately byte-oriented: exactly 8-bit external frames are supported, while 4–16-bit internal loopback is modeled. Narrower and wider external frames fault explicitly. There are no synthesized per-bit SCK/MOSI/MISO waveforms. A stock 64-byte full-duplex transfer is verified above MicroPython's DMA threshold through two contending DMA channels and the real TX/RX FIFOs. SoftSPI reads remain unsupported. Modeled: both harts in either mode — Hazard3 (RV32IMAC plus Zba/Zbb/Zbs/Zbkb/Zcb/Zcmp and the Hazard3 custom extensions) or Cortex-M33 (ARMv8-M Mainline with FPv5-SP, the 52-line NVIC, and the GPIO, double-precision and redundancy coprocessors) — in one deterministic global-cycle scheduler, independent interrupt/trap/timer/SIO-local state, the real core-1 boot FIFO handshake, cross-hart LR/SC and LDREX/STREX invalidation and stock MicroPython `_thread`; shared SIO/IO_BANK0/PADS_BANK0; all three PIO blocks (12 state machines); PWM; the 16-channel DMA and DREQ fabric; TIMER0/1 with TICKS or clk_sys sources; the RISC-V platform timer in ticked or full-speed mode; watchdog; boot RAM; XIP flash with QMI address translation; the required bootrom calls; UART0/1; ADC; USB CDC; I²C0/1 and SPI0/1. Not modeled: mixed-architecture operation (one core Arm, the other RISC-V), Arm Non-secure/TrustZone state, security-domain/ACCESSCTRL/PMP enforcement, PIO security partitioning, SPI slave/TI/Microwire modes, pin-level SPI waveforms, and dynamic execution-clock changes (both harts remain at 150 MHz even if firmware changes clock registers). DMA sniffing and the inaccessible XIP/QMI, HSTX, CoreSight and SHA DREQ producers remain fail-closed. Unsupported activation is fail-closed: UART IrDA/modem controls and PIO OUT_STICKY/INLINE_OUT_EN output arbitration stop with an explicit emulator fault.

gndvsysgp0gp1gp2gp3gp4gp5gp6gp7gp83v3gp16gp17gp18gp19gp20gp21gp22gp26gp27gp28
P2
Pi Pico 2 W
pipico2w

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Raspberry Pi Pico 2 W (real emulated RP2350 — Arm or RISC-V mode, as the image selects — + a modelled CYW43439 Wi-Fi/Bluetooth LE chip, 3.3 V logic) straddling the channel, anchor row e, 11 columns — the same 22-pin footprint as pipico2 (the radio hangs off internal GPIOs 23/24/25/29 that never reach the header, so GP25 is NOT the lamp on this board). Wire gnd + vsys (5 V in); the 3v3 pin is a real 3.3 V output. NO bundled firmware: props.firmware is either a user-uploaded "uf2:<base64>" image (Inspector upload — either official RPI_PICO2_W MicroPython build from micropython.org boots: the default Arm download or the RISC-V CPU mode variant) or empty, and an empty/omitted firmware leaves the board idle. AI-authored documents therefore cannot ship a runnable Pico 2 W — pick an ESP32 board for script projects and leave this part to users with their own UF2. The RP2350 side is exactly the pipico2 model: both harts in either mode, all three PIO blocks, the 16-channel DMA fabric, PWM, UART0/1, hardware I²C0/1 and SPI0/1 on the live FUNCSEL mux, ADC(26)/ADC(27)/ADC(28) against the real solved nets, watchdog, XIP flash and USB CDC — with the same not-modeled list (no mixed-architecture operation, no security-domain enforcement, no pin-level SPI waveforms, no dynamic execution-clock changes). The radio is the same CYW43439 model the Pico W uses, driven over the real cyw43-driver gSPI link (PIO program, both DMA channels, the ~226 KB firmware/NVRAM/CLM download) rather than a stub. With the MicroPython UF2 uploaded network.WLAN works for real on the same virtual air as the ESP32 and Pico W boards: scan, WPA2-PSK join, DHCP, sockets, board-to-board — networks come from props.wifi ("ssid:channel:rssi[:password]" comma list, editable live in the Inspector). It is station-only: network.WLAN(network.AP_IF) returns but creates no visible access point, so use props.wifi for board-to-board Wi-Fi. The onboard LED sits on the radio chip's GPIO0 — machine.Pin("LED") drives it, no RP2350 pin involved. Bluetooth LE works too: the CYW43439 is an HCI LE controller behind stock MicroPython's BTstack host, so the `bluetooth` module (and aioble) advertises, scans, connects and carries GATT in BOTH roles on the shared BLE air with the ESP32-C6 and the Pico W. Notify payloads clip at the default 20-byte ATT MTU. Pairing/bonding needs a custom build, exactly as on the Pico W: the official stock image ships no gap_pair. The radio is 2.4 GHz only, so it never receives a 5 GHz frame from a dual-band board. Not modeled beyond the pipico2 list: pin-level gSPI waveforms (the link is serviced at the FIFO-word level), and any CYW43439 mode the cyw43-driver does not itself drive.

gndvsysgp0gp1gp2gp3gp4gp5gp6gp7gp83v3gp16gp17gp18gp19gp20gp21gp22gp26gp27gp28

ESP32

ESP32
esp32

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Classic ESP32 DevKit (real emulated dual-core Xtensa LX6, 3.3 V logic). The simulation cycle clock is 160 MHz; CPU counter timing follows the guest-selected 80/160/240 MHz frequency. Boots unmodified ESP-IDF apps, official MicroPython (ESP32_GENERIC), and compiled Arduino-ESP32 sketches; the Code tab builds the fixed esp32:esp32:esp32 target and boots its merged flash image. Timer-group and RTC watchdog timeouts really reboot the chip and report their hardware reset reason. Timer-driven machine.deepsleep(ms) parks the cores in simulated time, then reboots with DEEPSLEEP_RESET + RTC wake reason; flash and RTC FAST/SLOW memory survive that wake. GPIO deep-sleep wake also works through EXT0 and EXT1 on the exposed RTC-capable g2/g4 pins: EXT0 matches one configured level; EXT1 supports ANY_HIGH or ALL_LOW. Use externally driven inputs or external pull resistors. UART wake and light sleep are not modeled. Wire gnd + vin (≥3.7 V; the onboard LDO makes the 3v3 output). Pins: gnd/vin/3v3/en + g2 (onboard LED), g4, g5, g18, g19, g21, g22, g23. props.firmware = "example:esp32classic-blink" | "bin:<base64 0xE9 image>" | "elf:<base64>". I²C defaults SDA=g21/SCL=g22; hardware SPI is FIXED on VSPI's pins SCK=g18/MOSI=g23/MISO=g19 — MicroPython: SPI(2) with no pin args (those ARE the port defaults); CS = any free GPIO you drive yourself; the byte-level seam attaches the microSD and SPI displays at bus speed. ADC on g2/g4 (ADC2, 0–3.3 V, 12-bit). Serial monitor = UART0. Its Wi-Fi station is on the shared virtual air: stock MicroPython v1.28.0 completes the real PHY/RF calibration, and scan, open/WPA2-PSK join, DHCP and sockets to the virtual router work. MicroPython native code emitters work on this board: @micropython.native and @micropython.viper compile a function to machine code (measured 2-3x and 20x+ on Python-level integer loops) — worth it only for a small leaf function doing measured-hot integer or ptr8/ptr16 work, not for C-call glue.

gndvin3v3eng4g5g2g21g22g23g18g19
ESP32-C3
esp32c3

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. ESP32-C3 module (real emulated RISC-V RV32IMC at 160 MHz, 3.3 V logic) straddling the channel, anchor row e, 11 columns. Its timer-group and RTC watchdogs use deadline-driven simulated time: feeds re-arm them, interrupt stages route through the real interrupt matrix, and reset stages reboot with the hardware reset reason. Timer-driven machine.deepsleep(ms) parks the core in simulated time, then reboots with DEEPSLEEP_RESET and timer wake reason; flash and 8 KB RTC FAST memory survive. Without an enabled timer it stays asleep until reset, including when only GPIO wake is configured. For automatic wake on C3, use machine.deepsleep(ms) with a positive duration. GPIO wake and light sleep are not modeled on C3. Wire gnd + vin (5 V in); the 3v3 pin is a real 3.3 V output. props.firmware = "example:esp32-blink" | "example:esp32-echo" | "bin:<base64 0xE9 image>" | "elf:<base64>". Measured Rust support is limited to esp-hal 1.1.2 digital GPIO/timekeeping with the default configuration, including its stack-guard watchpoint (the C3 trigger registers are modeled). Other Rust targets and hardware abstraction layer peripherals are not verified. I²C is FIXED at SDA=g8/SCL=g9 (MicroPython: I2C(0, scl=Pin(9), sda=Pin(8))); hardware SPI (GPSPI2) is FIXED at SCK=g6/MOSI=g7/MISO=g2 — MicroPython: SPI(1) with no pin args (those ARE the port defaults, same pins as the C6); CS = any free GPIO you drive yourself. The byte-level SPI seam attaches the microSD and the SPI displays (ST7735/ST7789/MAX7219/e-paper) at bus speed — prefer it over SoftSPI on this board. Arduino sketches use the same pins via an explicit SPI.begin(6, 2, 7) (SCK, MISO, MOSI); Adafruit_ST7735 and SD.h then work unmodified. ADC1 ch0-4 on g0-g4. Serial monitor = UART0. Its Wi-Fi station is on the shared virtual air: scan, open/WPA2-PSK join, DHCP, sockets and board-to-board traffic work. MicroPython native code emitters work on this board: @micropython.native and @micropython.viper compile a function to machine code (measured 2-3x and 20x+ on Python-level integer loops) — worth it only for a small leaf function doing measured-hot integer or ptr8/ptr16 work, not for C-call glue. An onboard WS2812 RGB LED sits on g8 as on the real C3-DevKitM-1: rgbLedWrite(8, r, g, b) (Arduino) or neopixel.NeoPixel(Pin(8), 1) (MicroPython) lights the pixel drawn on the board — no wiring, and g8 stays usable as a normal pin.

gndving0g1g2g3g4g5g6g7g83v3g9g10g18g19g20g21engnd25v3v3b
ESP32-S2
esp32s2

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Real emulated ESP32-S2 (single-core Xtensa LX7 at 240 MHz, 3.3 V logic), using the same 11-column curated footprint as the S3: gnd/vin/3v3 + g0-g10 and g18-g21. Wire gnd + vin (5 V in); the onboard regulator supplies the 3v3 pins. props.firmware = "example:esp32s2-blink" | "asset:/firmware/ESP32_GENERIC_S2-20260824-v1.29.0.bin" | a chip-matched "bin:<base64>" or "elf:<base64>" upload. The bare-metal fallback carries the S2 image chip id and S2 GPIO/UART addresses; it never aliases S3 bytes. Inspector offers the unmodified official ESP32_GENERIC_S2 MicroPython v1.29.0 full-flash image. The Code tab builds Arduino sketches with the fixed esp32:esp32:esp32s2 profile and loads its merged image. I²C is FIXED at SDA=g8/SCL=g9 (MicroPython: I2C(0, scl=Pin(9), sda=Pin(8))). The modeled GPSPI2 transaction seam is fixed at SCK=g6/MOSI=g7/MISO=g2; pass those pins explicitly rather than relying on board defaults. ADC1 channels 0-9 are g1-g10. Native USB-OTG device mode enumerates TinyUSB CDC firmware, so the serial monitor accepts and displays bidirectional CDC traffic while preserving UART0; firmware that mirrors console output onto both is de-duplicated. USB host mode and device classes other than CDC are not modeled. PCNT has four units and two channels per unit, routes through the GPIO matrix to any exposed GPIO, and supports the limits, thresholds, zero crossing, filter, interrupts, machine.Counter and machine.Encoder paths. The Wi-Fi station shares the virtual air. ESP32-S2 has no Bluetooth or 802.15.4 radio. An onboard WS2812 RGB LED sits on g18 as on the real S2-Saola-1: neopixel.NeoPixel(Pin(18), 1) lights the pixel drawn on the board — no wiring, and g18 stays usable as a normal pin.

gndving0g1g2g3g4g5g6g7g83v3g9g10g18g19g20g21engnd25v3v3b
ESP32-S3
esp32s3

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. Real emulated ESP32-S3 (dual-core Xtensa LX7, 240 MHz). Boots unmodified ESP-IDF, Arduino-ESP32, and MicroPython firmware. The Code tab's Arduino target matches the emulated DevKitC-1 profile: 4 MB flash and 8 MB octal PSRAM (esp32:esp32:esp32s3:FlashSize=4M,PSRAM=opi). Timer-group and RTC watchdog timeouts really reboot the chip and report their hardware reset reason. Timer-driven machine.deepsleep(ms) parks both cores in simulated time, then reboots with DEEPSLEEP_RESET + RTC wake reason; flash and RTC FAST/SLOW memory survive that wake. GPIO deep-sleep wake also works through EXT0 and EXT1 on the exposed RTC-capable pins: EXT0 matches one configured level; EXT1 supports ANY_HIGH or ANY_LOW. Use externally driven inputs or external pull resistors. UART wake and light sleep are not modeled. Same pin footprint as esp32c3 (gnd/vin/3v3 + g0-g10, g18-g21); I²C FIXED at SDA=g8/SCL=g9 (I2C(0, scl=Pin(9), sda=Pin(8))); hardware SPI (GPSPI2) is FIXED at SCK=g6/MOSI=g7/MISO=g2 — the S3's MicroPython SPI(1) defaults are off this footprint, so pass the pins explicitly: SPI(1, sck=Pin(6), mosi=Pin(7), miso=Pin(2)); CS = any free GPIO you drive yourself; the byte-level seam attaches the microSD and SPI displays at bus speed. ADC1 ch0-9 on g1-g10; serial console in the serial monitor. Its Wi-Fi station is on the shared virtual air: scan, open/WPA2-PSK join, DHCP, sockets and board-to-board traffic work. MicroPython native code emitters work on this board: @micropython.native and @micropython.viper compile a function to machine code (measured 2-3x and 20x+ on Python-level integer loops) — worth it only for a small leaf function doing measured-hot integer or ptr8/ptr16 work, not for C-call glue. An onboard WS2812 RGB LED sits on g48 as on the real S3-DevKitC-1: rgbLedWrite(48, r, g, b) (Arduino) or neopixel.NeoPixel(Pin(48), 1) (MicroPython) lights the pixel drawn on the board (g48 is not a header pin).

gndving0g1g2g3g4g5g6g7g83v3g9g10g18g19g20g21engnd25v3v3b
ESP32-C6
esp32c6

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. ESP32-C6 module (real emulated single RISC-V RV32IMAC at 160 MHz, 512 KB SRAM, 3.3 V logic) straddling the channel, anchor row e, 11 columns. Timer-group and LP watchdog timeouts really reboot the chip and report their hardware reset reason. Timer-driven machine.deepsleep(ms) parks the core in simulated time, then reboots with DEEPSLEEP_RESET + RTC wake reason; flash and LP/RTC memory survive that wake. GPIO deep-sleep wake works through EXT1 on g0-g7, with independently configured high/low levels and the exact waking pin mask. Use externally driven inputs or external pull resistors. C6 has no EXT0. UART wake and light sleep are not modeled. Wire gnd + vin (5 V in); the 3v3 pin is a real 3.3 V output. Boots unmodified ESP-IDF, Arduino-ESP32, and MicroPython firmware. Pins: gnd/vin/3v3 + g0-g9, g18-g20, g22, g23. props.firmware = "example:esp32c6-blink" | "bin:<base64 0xE9 image>" | "elf:<base64>". Zigbee coordinator firmware also ships as an asset: props.firmware = "asset:/firmware/arduino-zigbee-switch-c6.bin" makes the C6 an on/off ZCL coordinator — wire a pushbutton g9 → gnd (internal pull-up); after a sealed Zigbee appliance joins and binds (serial prints "Waiting for Light to bound", then the device short address), each press sends a real Toggle ("Toggling light" on serial). IMPORTANT for hand-authored docs: sealed Zigbee/Thread appliances need their props.firmware set EXPLICITLY to the asset id shown in their defaults — an omitted firmware boots a blink placeholder and the appliance never joins. I²C defaults SDA=g23/SCL=g22; hardware SPI (GPSPI2) is FIXED at SCK=g6/MOSI=g7/MISO=g2 — MicroPython: SPI(1) with no pin args (those ARE the port defaults); CS = any free GPIO you drive yourself. The byte-level SPI seam attaches the microSD and the SPI displays (ST7735/ST7789/MAX7219/e-paper) at bus speed — prefer it over SoftSPI on this board. Arduino sketches use the same pins via an explicit SPI.begin(6, 2, 7) (SCK, MISO, MOSI — the Arduino core's own defaults are NOT the contract pins); Adafruit_ST7735 and SD.h then work unmodified. ADC1 ch0-6 on g0-g6. An onboard WS2812 RGB LED sits on g8, exactly as on real C6 DevKits: rgbLedWrite(8, r, g, b) (Arduino) lights the pixel drawn on the board — no wiring, and g8 stays usable as a normal pin. Serial monitor: the C6 has TWO consoles and the panel merges both — compiled Arduino sketches are built with USB CDC on boot, so Serial is the USB-Serial-JTAG console and Serial0 is UART0; MicroPython and ESP-IDF mirror one console to both and show a single copy. All three radios are modeled: the Wi-Fi 6 station (scan/connect/DHCP/TCP on the virtual air), Bluetooth LE, and the 802.15.4 MAC that Thread and Zigbee run on (boards share the air; watch frames in the sniffer). MicroPython native code emitters work on this board: @micropython.native and @micropython.viper compile a function to machine code (measured 2-3x and 20x+ on Python-level integer loops) — worth it only for a small leaf function doing measured-hot integer or ptr8/ptr16 work, not for C-call glue.

gndving0g1g2g3g4g5g6g7g83v3g9g18g19g20g22g23engnd25v3v3b
ESP32-H2 DevKitM-1
esp32h2

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. ESP32-H2-DevKitM-1 with a real emulated single RV32IMAC core at 96 MHz, 320 KB HP SRAM, Bluetooth LE 5 and IEEE 802.15.4 for Thread/Zigbee. It deliberately has no Wi-Fi. The footprint follows the physical two-row 30-pin board: repeated ground pins, 3V3, 5V, VBAT, RST, USB D-/D+ on g26/g27, and exposed GPIOs in official header order. Wire any GND plus 5V (or VBAT); 3V3 is the regulated output. I²C defaults to SDA=g12/SCL=g22; fixed SPI is SS=g0/SCK=g10/MOSI=g25/MISO=g11; ADC1 channels are g1-g5; the onboard RGB LED is on g8. props.firmware accepts the default example:esp32h2-blink, bundled secure-BLE/OpenThread/Zigbee/802.15.4 assets, chip-matched ESP-IDF/Arduino bin images, or ELF. The Inspector picker exposes those radio programs. Arduino compilation uses server-allowlisted esp32h2, esp32h2-openthread, esp32h2-zigbee-coordinator, and esp32h2-zigbee-device profiles; user FQBN flags are never accepted. There is no official ESP32-H2 MicroPython port, so Breadboard does not offer or generate MicroPython firmware for this board.

3v3rstg0g1g2g3g13g14g4g5ncvbatgnd5vgnd2gnd3g24g23g10g11g25g12g8g22gnd4g9gnd5g27g26gnd6
ESP32-C5-DevKitC-1
esp32c5

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. ESP32-C5-DevKitC-1 v1.2 (N8R8) with a real emulated single RISC-V RV32IMAC core at 240 MHz behind a CLIC interrupt controller. It is the bench's only DUAL-BAND board: its Wi-Fi 6 station scans and joins networks on 2.4 GHz AND 5 GHz (channels 36-177), and a 2.4 GHz-only board given the same document spec genuinely cannot see the 5 GHz ones — a scan on each board shows the difference. It also carries the 802.15.4 MAC that Thread and Zigbee run on. Boots unmodified ESP-IDF images and the official MicroPython v1.29.0 ESP32_GENERIC_C5 release to a live Python REPL (the @micropython.native and @micropython.viper code emitters work here too); the Inspector picker offers MicroPython plus three bundled vendor ESP-IDF programs (hello_world, the IEEE 802.15.4 radio CLI, and the NimBLE bleprph Bluetooth LE peripheral). No prebuilt Arduino-ESP32 C5 image ships — Arduino sketches reach this board through the cloud compile service, which serves the C5 only once the operator has enabled its rollout latch. The footprint follows the physical two-row 32-pin board in silkscreen order: 3V3, RST, the exposed GPIOs, 5V, four grounds and four NC pads. Wire any GND plus 5V; 3V3 is the regulated output and RST resets the chip. GPIO16-22 are bonded to the module's flash and PSRAM and reach no header (g15 is the NC pad on this module). I²C is FIXED at SDA=g23/SCL=g24 — the MicroPython C5 port ships no usable default pair, so always pass both pins: I2C(0, scl=Pin(24), sda=Pin(23)). ADC1 ch0-5 are on g1-g6 and there is no ADC2. UART0 is TX=g11/RX=g12, USB-Serial-JTAG is on g13/g14, and the serial monitor merges both consoles into one copy. BOOT is on g28 and the onboard WS2812 RGB LED on g27, which the bundled example:esp32c5-blink image drives directly. Arduino compilation targets esp32:esp32:esp32c5 and its image is written from flash 0x2000, because the C5 is a key-manager part. Digital pin I/O is fully modeled: the C5 lays its GPIO block out differently from the rest of the C6 family (ENABLE at 0x034, IN at 0x064, PINn at 0x0d4, wider matrix selectors) and the emulator follows the C5's own map, so machine.Pin writes and reads reach a real pad — LEDs, buttons, the onboard neopixel and SPI chip-select all work. Hardware SPI uses the same modeled GPSPI2 byte seam as the C3/C6 at SCK=g6/MOSI=g7/MISO=g2, but pass those pins explicitly: SPI(1, sck=Pin(6), mosi=Pin(7), miso=Pin(2)). PCNT has four units and two channels per unit routed through the GPIO matrix, with the C5's own wider register file (a four-register per-unit CONF block and a step-notify comparator). Bluetooth LE works in both roles on the same air as the C6 and H2 boards, GATT included. Not modeled: pin-level SPI/I²C waveforms, and SoftI2C/SoftSPI (as on every board).

3v3rstg2g3g0g1g6g7g8g9g10g26g255vgndnc1gnd2g11g12g24g23nc2g27g4g5nc3g28gnd3g14g13gnd4nc4
S31DEV
ESP32-S31 (development source)
esp32s31

Pinned development-source model (ESP-IDF c712a0dd, rev0 ROM). Logical GPIO layout, not a physical development board. Power SIM VIN at 5 V and GND; 3V3 OUT is a modeled supply. Two HP RISC-V harts; core0 starts after a modeled ROM/bootloader handoff and core1 executes the real ROM launch. Supported: GPIO (GPIO0–7 as HP pads: gpio_config() and gpio_reset_pin() select their HP IO MUX), UART0 8N1, UART1/UART2 8N1 byte lines on GPIO-matrix pads (equal baud at both ends; UART3 has no pad route in the pinned driver), AT_CMD pattern detection on UART0–UART2 (a line typed in the Serial panel arrives as one burst of back-to-back characters; cases the pinned sources leave undefined, such as a fourth + after a three-+ pattern with no idle time, stop with a diagnostic), bounded I2C0 byte transactions (a 7-bit master through the pinned i2c_master driver, including its default SCL/SDA glitch filters and the probes of every address 0x00–0x7F that the i2c_tools scan sends; bench parts answer only their own address, never the general call, and none sits at 0x78–0x7B, so commands there fail like any absent device (those bytes are also 10-bit prefixes; 10-bit devices are not modeled, so 10-bit transfers fail the same way, and a device answering a prefix would stop with a diagnostic); a pulse a filter would ignore during a transfer stops with a diagnostic; after an i2cget, i2cset or i2cdump times out on a held SDA or SCL line, the next one asks for a bus clear, which stops the board with a diagnostic until Restart; after an i2cget or i2cdump to an absent address, an i2cdetect stops the same way when it reaches a device, because the pinned driver then reads its empty receive FIFO, so first run i2cconfig, any i2cset, or an i2cget that a device answers) and bounded source-defined profiles for GPSPI2/3 (single-line master, no DMA), LEDC (timers 0/1, channels 0–3, XTAL; 1–20-bit resolution with integer or fractional dividers, a fraction only at 8 bits or more; single-range hardware fades with the fade-end interrupt), RMT (TX channels 0–3 with finite loops; RX channels 0–3 only through a TX loopback pad), PCNT0 (units 0–3), TIMG0/1 T0/T1 general-purpose timers (XTAL or REF_F80M, counter capture, software load, alarms and auto-reload interrupts; a functional profile bounded by the stock gptimer example's vendor ranges; any alarm/reload register write or count load while running with the alarm armed stops with a diagnostic, as does a count read before UPDATE capture; arming an alarm at least 2^53 counts past its target in the counting direction stops because the pinned vendor tests disagree) and MCPWM0 (timers 0–2 counting up, operators 0–2 with generator A, continuous force, and timer sync from a GPIO input with phase 0; the sync input reads its pad like GPIO_IN, so an input-disabled pad reads low; a reload whose effect the pinned sources leave open, a sync reaching a stopped timer and a peripheral output looped into a sync input stop with a diagnostic). The pinned PCNT and MCPWM servo examples use GPIO0/GPIO2, the mcpwm_sync example GPIO0/2/4 with its own sync pulse on GPIO5, the UART example GPIO4/GPIO5, the generic_gpio example GPIO18/19 wired to GPIO4/5, the ledc_basic example GPIO2, the ledc_fade example GPIO8/9/2/3, the i2c_basic example SCL GPIO4 and SDA GPIO5 to an MPU-6050 (it prints WHO_AM_I = 68), the i2c_tools example the same wiring through its Serial-panel commands (i2cconfig --sda 5 --scl 4, then i2cdetect, i2cget -c 0x68 -r 0x75, i2cset or i2cdump), the uart_events example only the Serial panel (type +++ for its pattern event), the gptimer example only the Serial panel (stopped/set/reloaded/alarmed counts), and the unmodified wiegand_interface example GPIO0 for zero and GPIO2 for one (26 descending bits of 0x5a5a5a5a, low pulses of nominally 50 us on a 1000 us period; the bench shows each edge within one 10 us solver step, so measured widths can differ by up to one step); use GPIO0–61 except package holes 29/41. GPIO30–34 are reserved by the pinned flash driver, GPIO36 is the flash-LDO strap, and GPIO58/59 carry the console. LP IO functions of GPIO0–7 (LP IO MUX selection, pad hold, LP GPIO), other alternate functions and peripheral modes outside these profiles (for example SPI slave or DMA, UART flow control or other framings, LEDC gamma-curve (multi-range) fades, fade pause or duty dithering, the RMT carrier, MCPWM capture, timer-to-timer or software sync, generator B or dead time, TIMG RC_FAST, ETM routes or sleep retention), PSRAM, radios, MicroPython, cloud compile and physical flashing are unsupported. Unsupported execution stops with a diagnostic. Firmware radio feature text is chip metadata, not simulated radio support. The public Examples gallery includes the unmodified pinned servo sweep, rotary encoder, four fading LEDs, MPU-6050 identity, rainbow ring and musical buzzer programs, with their accepted wiring and Serial output; enable verbose in Serial to see their upstream INFO lines.

vingnd3v3g0g1g2g3g4g5g6g7g8g9g10g11g12g13g14g15g16g17g18g19g20g21g22g23g24g25g26g27g28g30g31g32g33g34g35g36g37g38g39g40g42g43g44g45g46g47g48g49g50g51g52g53g54g55g56g57g58g59g60g61
P4
ESP32-P4-Function-EV-Board
esp32p4

New palette placements have USB cable power connected. Use the Inspector's USB cable control to unplug it before testing an external supply. Saved circuits retain their existing power wiring. Power does not install firmware. ESP32-P4-Function-EV-Board v1.5.2: two 400 MHz RV32 RISC-V cores with single-precision FPU, 16 MB flash and 32 MB PSRAM. Chip revision in the Inspector selects 3.2 (default) or 3.0 (beta), saved per board as p4Revision=302 or 300. Changing it restarts the simulation. The beta profile has source and firmware regression coverage but no current physical rev3.0-board comparison. J1 is the physical 2x20 header, with 23 live GPIOs up to g54, eight grounds, two 5V pins, two 3V3 outputs and five NC contacts. Power 5v or 5v2 plus any GND. GPIO0/1/45 require board modifications and remain NC; positions 27/28 are also NC. No onboard RGB pixel: example:esp32p4-blink runs compiled Arduino ESP32 3.3.10 and toggles external GPIO6 every 0.5 s. The MicroPython picker uses pinned v1.29.0 sources built for rev3 UART/USB Serial-JTAG, with radio dependencies and USB-OTG disabled; the official pre-rev3 binary is incompatible with the rev300 ROM. Both I2C controllers and SPI2/3 follow live GPIO-matrix routes. Pass explicit J1 pins: I2C(0,scl=Pin(7),sda=Pin(8)); SPI(1,sck=Pin(21),mosi=Pin(22),miso=Pin(23)) with manual CS on g36, or SPI(2,sck=Pin(47),mosi=Pin(48),miso=Pin(54)) with CS on g46. These leave GPIO37/U0TXD and GPIO38/U0RXD free. I2C defaults are SCL18/SDA19 for I2C0 and SCL9/SDA8 for I2C1; neither pair is fully exposed on J1. SPI defaults are SCK9/MOSI8/MISO10 for SPI(1), SCK43/MOSI44/MISO39 for SPI(2); neither triple is fully exposed. ADC1 maps GPIO16-23 and ADC2 GPIO49-54, so J1 exposes ADC on g20-g23 and g53-g54. GPIO, static LEDC PWM and bounded single-range LEDC hardware fades, RMT transmit, PCNT and byte-level I2C/SPI are modeled. Stock ESP-IDF v5.5.4 ledc_fade runs through the real fade-end interrupt and callback on GPIO8/9/4/5. Wire external LEDs to g8/g4/g5; g4/g5 are inverted in that example. The driver quantizes its requested 3000 ms fade to about 2.0032 s. During a nonzero fade, ledc_fade_stop, ledc_stop, duty retargeting, timer frequency changes and timer resets are unsupported. Fractional source-clock fade periods are also unsupported. No per-bit I2C/SPI waveforms, arbitration, clock stretching, SoftI2C, SPI slave/multiline/command phases, LEDC multi-range gamma/phase/RC_FAST, RMT RX/carrier/continuous mode, LP core or media. USB OTG HS runs one bounded device path: ESP-IDF TinyUSB CDC-ACM firmware (buffer DMA) enumerates at high speed against the bench host, typed serial becomes CDC data once the device is configured, and the CDC echo joins the serial stream beside UART0. A TinyUSB mass-storage (MSC Bulk-Only) function beside CDC-ACM appears in the USB disk view of the Inspector: the bench host probes it (GET MAX LUN, TEST UNIT READY, READ CAPACITY, INQUIRY), lists and reads FAT12/16 files, and rewrites a file within the clusters it already owns with READ(10)/WRITE(10). It clears stalled endpoints and runs Bulk-Only Reset Recovery when a transfer goes wrong. Disk requests are recorded inputs, so recordings replay them exactly. Firmware sees host writes when it next mounts the volume, for example after a reset. LUNs other than 0, other SCSI commands, creating or growing files, long file names and FAT32 are unsupported. USB host mode, full-speed OTG, other device classes, slave-FIFO or descriptor DMA and suspend/resume fault. The original console network module imports but has no WLAN. Separately select MicroPython C6_WIFI and p4Companion=hosted-2.7.0-wpa2-psk-sta for the deterministic native ESP-Hosted 2.7.0 companion over modeled SDMMC/SDIO/IDMAC: a 2.4 GHz STA on channels 1–11 that joins open and WPA2-PSK (CCMP) networks with scan/connect, DHCP and TCP/UDP through the simulated AP/router. Peer boards are reachable on open networks only. Like the real companion, connect() first scans every channel (about 2.4 s) and then joins the strongest network with that SSID. A wrong password reports STAT_HANDSHAKE_TIMEOUT (204) after 10 s and STAT_WRONG_PASSWORD on the next retry. Documents that carry the retired id p4Companion=hosted-2.7.0-open-sta load and run on the same companion. GPIO54 is companion EN/reset; keep it high and choose another LED/SPI pin when networking. Bluetooth LE comes through the same companion for Arduino-ESP32 3.3.10 sketches that use the bundled BLE library: the sketch enables the C6 controller of the companion through ESP-Hosted and runs on the shared BLE air with legacy advertising and one connection. Verified: the unmodified BLE Server example advertises, accepts a connection and serves GATT reads to an ESP32-C6 central. Scanning is not modelled yet (LE Set Scan Parameters answers Unknown HCI Command), the central role and pairing are not verified, resolvable private addresses are refused, and LL length/PHY updates are not modelled. The MicroPython bluetooth module still fails with OSError 116: that image never enables the controller. WPA/WPA3, PMF, Enterprise, SoftAP, ESP-NOW, Thread, Zigbee, general SD cards and LAN/PPP remain unsupported. The emulated TRNG is deterministic: random bytes and SSL material repeat across identical runs/snapshots and are not cryptographic entropy. Unsupported peripheral actions fault. Arduino compilation uses a fixed rev3 UART/USB Serial-JTAG profile when enabled on the server (16 MB flash, sketch PSRAM disabled). Compiled Arduino artifacts can be flashed through Chromium WebSerial to P4 revision 3.0/ECO5 with 16 MB flash over J19 USB Serial/JTAG or an external UART0 reset bridge; other revisions, USB-OTG and secured chips are refused. J19 can stay silent because this profile prints Serial on UART0.

Use the rev3 console-profile image, not the official pre-rev3 download.
Random/SSL material repeats across identical runs and snapshots; it is not cryptographic entropy.
USB OTG HS supports only high-speed TinyUSB CDC-ACM device firmware with buffer DMA, plus a composite MSC function in the USB disk view (in-place file edits only); host mode, full-speed OTG and other classes fault.
3v35vg75v2g8gndg23g37gnd2g38g21g22g20gnd3g6g53v3bg4g3gnd4g2nc1nc2g36gnd5g32nc3nc4g33gnd6g26g54g48gnd7g53g46g47g27gnd8nc5

Basics

Resistor
resistor

props.resistance in ohms; props.maxPower rating in watts (0.25 default); exceed it long enough and it burns open.

ab
R ×8
Resistor array ×8
resistorarray

Eight independent resistors in one DIP-16 straddling the channel (4116R-1-style isolated pack). Element k joins pin pk (bottom row, left to right) to pin p(17−k) — the pin directly above it. One shared props.resistance for the whole pack, like the real single-value part; each element is rated 0.25 W and burns open individually. Ideal for an 8-LED bank or seven-segment series resistors: one package instead of eight bodies.

p1p2p3p4p5p6p7p8p9p10p11p12p13p14p15p16
Inductor
inductor

props.inductance in henries (e.g. 0.01 = 10 mH). ~1 Ω winding resistance modeled; DC = near-short.

ab
LED
led

props.color: red|green|blue|yellow. Pin a = anode (+), k = cathode. ALWAYS use a series resistor (220–470 Ω at 5 V); sustained >30 mA burns it out.

ak
Capacitor
capacitor

props.capacitance in farads (100e-6 = 100 µF).

ab
Text label
label

Text annotation with NO electrical function. Anchor on any free hole; props.text is the displayed string (multi-line allowed). Long text collapses to a one-line preview — clicking the label (or props.expanded=true) expands it into a wrapped block. Use to title boards or explain circuit sections.

anchor

Power

5V
Battery
battery

Leads side by side: + on the anchor, − one column to its right. To bridge the rails press R once (rotation 90) and anchor ON a "B+n" rail hole; the − lead lands on "B-n" below it. At rotation 0 or 180 both leads land on the same rail: a dead short that reads 0 V. Off the rails, wire its two pins. Provides the ground reference automatically. props.voltage 1.5–12 V.

posneg
Fuse
fuse

props.currentRating in amps (0.5/1/2/5). Blows open on sustained over-current (i²t); place in series with the supply.

ab
7805
7805 Reg
reg7805

Linear 5 V regulator, pins in/gnd/out. Needs ≥7 V at in; out holds 5 V.

ingndout
12V
DC Jack
barreljack

12 V wall supply. Anchor ON a "B+n" rail hole; − lands on "B-n" below it. props.voltage.

posneg
Buck Conv
buckconverter

DC-DC step-down: vin/gnd in, vout/gnd2 out. props.outputVoltage (default 5).

vingndvoutgnd2

Input & control

Button
pushbutton

Momentary SPST between pins a and b; the user clicks it to close.

ab
Toggle switch
switch

Latching SPST toggle between pins a and b. props.closed (boolean, default false) is the lever position and persists with the document; the user clicks the lever to flick it.

ab
Trim Pot
potentiometer

props.resistance = track ohms, props.position 0–1 = wiper spot. Pins a / wiper / b.

awiperb
Keypad 4×4
keypad4x4

4×4 matrix keypad: pressing key (row r, col c) connects pin r0-r3 to c0-c3, so standard MCU scanning firmware works. Hold a key on the canvas to press it; releasing the pointer releases the contact. With Keypad 3.1.1 on UNO R4 WiFi, add four physical 10 kΩ pull-up resistors from r0-r3 to 5 V: its AVR compatibility fallback does not enable the RA4M1 row pull-ups, so floating rows give phantom keys. Keypad 3.1.1 carries GPL-3.0 LICENSE terms with LGPL-2.1 source headers; resolved builds get one source/licence note.

r0r1r2r3c0c1c2c3
Joystick
joystick

Two-axis analog joystick (KY-023). Pins: vcc/gnd/vrx/vry/sw. VRx/VRy are wiper voltages (0..VCC) an ADC reads; sw closes to GND when pressed (add a pull-up). With Select active, drag the stick cap or surrounding dark gimbal well on the canvas for live axes; click or hold the cap without moving for the switch. Focus the canvas to use arrows/WASD and Space for the same transient controls. A sole joystick is targeted automatically; select one first when there are several. Inspector props.x, props.y (0–1), and props.pressed are saved defaults/calibration, not a live gesture log.

gndvccvrxvrysw
vcc: supply for both axis potentiometers
gnd: ground and the switch return
vrx: X-axis wiper voltage, 0–VCC
vry: Y-axis wiper voltage, 0–VCC
sw: active-low momentary switch; add a pull-up
DIP Switch
dipswitch

4 independent SPST switches: a0/b0 … a3/b3, straddling the channel. User toggles them.

a0a1a2a3b0b1b2b3
Encoder
encoder

Rotary encoder: quadrature a/b close to com as the user turns it. Wire com → gnd and add ~10 kΩ pull-ups from 3v3 to a and b (a closed contact then reads LOW). Poll the two phases as plain inputs, or — on the ESP32 boards that have one — let the HARDWARE PULSE COUNTER (PCNT) track the shaft: MicroPython's `machine.Encoder(0, phase_a=Pin(4), phase_b=Pin(5))` counts detents in the background and `value()` reads the running total, positive one way and negative the other. `machine.Counter(0, src=Pin(n), direction=Counter.UP)` is the same peripheral counting plain pulses on one pin — use it for flow meters, tachometers and frequency counting. Both accept ANY GPIO: PCNT inputs route through the GPIO matrix, unlike the fixed I²C/SPI pins.

Arduino cloud compile provides RotaryEncoder 1.6.0 (`RotaryEncoder.h`) and Encoder 1.4.4 (`Encoder.h`). Call RotaryEncoder.tick() often enough to see both contact edges; Encoder is admitted only on Arduino AVR.
PCNT exists and is modeled on the classic ESP32 (8 units), ESP32-S2, ESP32-S3, and ESP32-C6 (4 units each on the newer chips). ESP32-C3 silicon has no PCNT peripheral.
The default decode is x1: one count per FULL detent, i.e. per four quadrature steps. Turning the knob four clicks moves value() by one, not four.
The counter hardware is 16-bit signed. MicroPython's Counter/Encoder wrap that in a ±32000 limit interrupt and accumulate beyond it, so value() keeps growing — the raw peripheral would wrap.
Never read a floating phase. Without the pull-ups (or Pin.PULL_UP on the C3/S2/S3/C6) both phases read garbage, exactly like real hardware.
acomb
a: Phase A contact — closes to com on the Gray sequence.
b: Phase B contact, a quarter cycle out of phase with a.
com: Common contact; wire to gnd with pull-ups on a and b.

Motors & output

Relay
relay

SPDT. Energize the coil (~70 Ω, needs ~45 mA through coilA→coilB) to switch com from nc to no. The coil is inductive, so put a flyback diode across it (cathode to the driven side).

coilAcoilBcomnonc
RGB LED
rgbled

Common-cathode RGB LED: r/g/b anodes + shared k. Series resistor per channel.

rkgb
Buzzer
buzzer

props.kind: "active" (DC in → 2.4 kHz beep) or "passive" (follows drive frequency, e.g. from a 555).

posneg
Servo
servo

RC servo: 50 Hz pulses on sig, 1–2 ms width = 0–180°.

gndvccsig
DC Motor
motor

Small DC motor (~20 Ω winding). Spins proportional to voltage.

ab
Stepper (28BYJ-48)
stepper28byj

28BYJ-48 geared stepper WITH its ULN2003 driver board — one part, because that is how every kit ships the pair. Header order: in1 · in2 · in3 · in4 · vcc · gnd, all in one row (nothing straddles the channel). Wire in1–in4 to four GPIOs and vcc/gnd to a 5 V supply — this is a real load, about 100 mA per energized phase (100–200 mA while stepping), so feed it from the supply, never from an MCU 3V3 pin. 3.3 V logic drives the inputs fine: each is a 2.7 kΩ base resistor behind two Vbe drops (~1.4 V), and TI guarantees turn-on at VI ≤ 2.7 V even at 250 mA of collector current. Step it by walking the 8-state HALF-STEP ring, one pattern change per step: in1 → in1+in2 → in2 → in2+in3 → in3 → in3+in4 → in4 → in4+in1 → (back to in1). Walk it backwards to reverse. FULL-STEP drive is the same ring taken two entries at a time and works too, in either flavour: the 1-phase wave sequence (in1, in2, in3, in4) or the stronger 2-phase-on sequence (in1+in2, in2+in3, in3+in4, in4+in1). Patterns that are not on the ring hold no rotor position at all, so they are skipped rather than counted — which is why setting your four pins one at a time works fine, and why the in1+in3 / in2+in4 pair a mis-ordered Stepper.h emits turns the shaft NOT AT ALL, the same "it only buzzes" symptom as the real motor. Jumping more than one full step around the ring in one go does not move the shaft either. GEARING: 32 full steps (64 half steps) per rotor turn through a 63.68395:1 gearbox, so one revolution of the OUTPUT shaft is 4075.7728 half steps (2037.886 full steps), not the 4096/2048 hobby code rounds to — assume 4096 and you come up ~0.5 % short every turn. ARDUINO: Stepper.h is not installed in Breadboard’s compile image. Arduino cloud compile provides TinyStepper_28BYJ_48 1.0.0 (`#include <TinyStepper_28BYJ_48.h>`), AccelStepper 1.64.0 (GPL-3.0; FULL4WIRE pin order IN1/IN3/IN2/IN4) and CheapStepper 0.2.1 (GPL-3.0; Arduino AVR and Uno R4 only). Without a library, set the four GPIOs to OUTPUT with pinMode, then use digitalWrite to walk the half-step ring above, with delay(2) after each complete pattern. For in1=d8, in2=d9, in3=d10, in4=d11, write the pattern entries to pins 8, 9, 10, 11 in that order. If you use the separately installed Stepper library in your own build, its full-step constructor instead needs IN1, IN3, IN2, IN4: Stepper motor(2048, 8, 10, 9, 11). MICROPYTHON: there is no stepper driver module on the stock images (the import fails), so write the loop — `from machine import Pin` / `import time` / `pins = [Pin(n, Pin.OUT) for n in (3, 4, 5, 10)]` / `SEQ = ((1,0,0,0),(1,1,0,0),(0,1,0,0),(0,1,1,0),(0,0,1,0),(0,0,1,1),(0,0,0,1),(1,0,0,1))` / `for _ in range(64):` / ` for s in SEQ:` / ` for i in range(4): pins[i].value(s[i])` / ` time.sleep_ms(2)`. TIMING: the rotor has a real follow time — a field must be HELD about 0.5 ms before the shaft is on it, because a real 28BYJ-48 tops out near 1000 steps/s and cannot chase anything faster. Measured on the emulated ESP32-C3 bit-banging the sequence in MicroPython (the four pin writes plus loop overhead cost ~32 µs, so the sleep is nearly the whole period): a 512 µs period landed all 64 of 64 half steps, 482 µs landed 1, and 432 µs and below landed none at all — the field just runs away, exactly like a real motor asked to slew too fast. Use time.sleep_us(500) as the floor and 2 ms (≈500 half steps/s) as a comfortable pace. That same follow time is what makes the mis-ordered Stepper.h trap behave like hardware: the microsecond-scale patterns between two consecutive digitalWrites are transients the shaft never reaches. MODELLED: phase current, the Darlington input load, the ring recognizer in both directions and all three drive modes, the geared output angle, and the four channel LEDs. NOT MODELLED: winding inductance (phases are resistive — the board clamps its own flyback, and stepper torque does not need it, unlike the relay part where the spike IS the point); the Darlington saturation drop (0.9 V typ at 100 mA), so a phase draws the ideal 100 mA where real hardware measures ~82 mA; and torque, inertia and load — the follow time is the only mechanics, so above it every legal transition lands and below it none do, where a real motor loses steps gradually as you load it. With vcc below 2 V the inputs still switch but no phase draws current and the shaft does not move, like the real board.

Arduino cloud compile provides TinyStepper_28BYJ_48 1.0.0 (`TinyStepper_28BYJ_48.h`), AccelStepper 1.64.0 (`AccelStepper.h`) and CheapStepper 0.2.1 (`CheapStepper.h`). AccelStepper/CheapStepper carry GPL-3.0 terms and a resolved-build source/licence note. CheapStepper is admitted only on AVR/Uno R4; its pinned source does not compile on ESP32. AccelStepper FULL4WIRE uses IN1/IN3/IN2/IN4; keep physical step dwell above 0.5 ms.
The four board LEDs sit on the OUTPUTS: with the supply off the inputs still toggle, but nothing lights and nothing turns.
The shaft marker moves 0.0883° per half step. Watching a single step do nothing visible is correct — 4076 of them make one turn.
in1in2in3in4vccgnd
120mm Fan
pwmfan

4-pin 120 mm fan: gnd, v12 (needs 12 V!), tach (open-collector, add a pull-up), pwm control input. props.maxRpm.

gndv12tachpwm
40mm Fan (5V)
fan40

2-wire 40 mm 5 V fan (pos, neg — ~25 Ω load): no PWM/tach pins, exactly like the real Pi-class part. Full speed across 5 V, stalls below ~1.5 V, never spins reversed; for speed control switch/PWM the supply side with a transistor. props.maxRpm.

posneg
NeoPixel ×8
ws2812

NeoPixel strip, 8 addressable RGB LEDs. Wire din from an MCU pin and run firmware "example:neopixel" (uses D2). 5 V on vcc.

vccdingnd
NeoPixel ring ×12
ws2812ring12

NeoPixel ring, 12 addressable RGB LEDs (5050) with pixel 0 beside the pads. Same WS2812 protocol as the strip: wire din from an MCU pin, 5 V on vcc. MicroPython: neopixel.NeoPixel(Pin(n), 12).

vccdingnd
NeoPixel ring ×24
ws2812ring24

NeoPixel ring, 24 addressable RGB LEDs (5050) with pixel 0 beside the pads. Same WS2812 protocol as the strip: wire din from an MCU pin, 5 V on vcc. MicroPython: neopixel.NeoPixel(Pin(n), 24).

vccdingnd
Laser (KY-008)
laser

KY-008 laser emitter. Pins: s (signal), vcc, gnd. Power vcc (≥2.7 V) and drive s HIGH to emit; tie s to vcc for always-on. Pairs with a photoresistor as a break-beam tripwire.

svccgnd
s: emit control: logic high turns the beam on
vcc: 2.7–5 V supply
gnd: ground

Displays

7-Segment (1 digit)
sevenseg

Common-cathode SINGLE-DIGIT 7-segment, straddles the channel (anchor row e). Segment pins a–g + dp, common = com. Series resistors per segment. Arduino cloud compile provides SevSeg 3.7.0 (`#include <SevSeg.h>`); select COMMON_CATHODE, use segment resistors and call `refreshDisplay()` on every loop pass: begin() blanks the display and setNumber() only stores the digit, so a single digit stays blank without it.

edcomcdpgbfa
7-Segment (4 digits)
sevenseg4

4-digit common-cathode 7-segment module, 12 pins (5641AS pinout), straddles the channel. The 8 segment lines a–g+dp are SHARED across all four digits; each digit has its own common-cathode pin dig1–dig4. Firmware must multiplex: drive one digit's segments, pull only that digit's common LOW (others HIGH/input), hold ~1–2 ms, move on — the emulator integrates duty like the eye does, so a properly multiplexed display shows steady digits. Series resistors go on the 8 SEGMENT lines (one per segment, e.g. 220 Ω), never on the commons. Arduino cloud compile provides SevSeg 3.7.0 (`#include <SevSeg.h>`): select COMMON_CATHODE and call `refreshDisplay()` on every loop pass, or the digits stay blank. Bottom row: e d dp c g dig4; top row: dig1 a f dig2 dig3 b.

Arduino cloud compile provides SevSeg 3.7.0 (`#include <SevSeg.h>`). Use COMMON_CATHODE, segment resistors and regular refreshDisplay() calls for multiplexing.
Two commons low at once light BOTH digits with the same pattern (ghosting) — the emulator reproduces this like the real part.
A digit is off unless its common is actively low; refresh all four digits faster than ~60 Hz or they visibly dim/flicker.
Resistors on the digit commons (instead of segments) make brightness vary with how many segments are lit.
eddpcgdig4dig1afdig2dig3b
7-Segment (TM1637)
tm1637

TM1637 4-digit 7-segment clock module — the driver chip does the multiplexing, so it is just four pins in one row: gnd · vcc (3.3–5 V) · dio · clk. The bus LOOKS like I²C and is NOT: no address byte, bits go out LSB FIRST, and the chip acknowledges each byte by pulling dio low during a 9th clock. Framing is I²C's (START = dio falling while clk high, STOP = dio rising while clk high, bits valid on the clk rising edge). Commands: 0x40 data write with auto-increment (0x44 = fixed address), 0xC0–0xC3 pick digit 1–4, 0x88|n turns the display on at brightness n (0–7). A digit byte is bit0 = a … bit6 = g; bit7 is the colon, and only the SECOND digit (0xC1) actually drives it on this module. A typical write is three frames: [0x40], then [0xC0, d1, d2, d3, d4], then [0x88|brightness]. Brightness is the datasheet pulse width (1/16 at level 0 up to 14/16 at level 7), so level 0 really does look nearly off. UNO R4 WiFi observes accepted solved CLK/DIO wire levels, including open-drain release and ACK; TM1637_RT 0.5.0 is verified with begin(clockPin, dataPin, 4) and setBitDelay(50). Other MCU adapters decode cycle-exact GPIO edges, so those masters must DRIVE both lines to each level (push-pull writes): letting a pin float up to the module pull-up releases the pad without a GPIO write and the frame is not seen — the one exception is releasing dio for the ack clock, which is exactly what you should do. There is no tm1637 driver module on the stock MicroPython images (import fails), so in MicroPython bit-bang it yourself with machine.Pin + time.sleep_us(50). Arduino cloud compile provides TM1637_RT 0.5.0 (`#include <TM1637.h>`): select four digits in begin(clockPin, dataPin, 4) and call setBitDelay(50). On the cycle-edge adapters the WRITE path is cycle-exact and pace-independent (measured correct from sleep_us(200) all the way down to sleep_us(1)); the ACK READ is the one thing that needs settling time, because the module's pull-down only reaches the guest after the next solve. Measured on the emulated ESP32-C3: with a normal sleep between the 8th falling clock and the DIO sample the ack read low at every pace tested, and it was only missed when the ack window had NO delay at all and the rest of the frame ran at sleep_us(1). Leave at least ~10 µs there — sleep_us(50) is comfortable. Keys: this module has no buttons, and the 0x42 key-scan read returns 0xFF from the bus pull-ups — which is the hardware value for "no key pressed".

Arduino cloud compile provides TM1637_RT 0.5.0 (`#include <TM1637.h>`). Select four digits in begin(clockPin, dataPin, 4); setBitDelay(50) is verified on the bench. The library's default 10 microseconds is not yet verified.
The colon lives in bit 7 of the SECOND digit (address 0xC1), not in a digit of its own.
The display powers up blank: nothing shows until a 0x88|n display-control command turns it on.
gndvccdioclk
OLED
OLED 128×64
ssd1306

SSD1306 128×64 OLED, I²C address 0x3C. Wire scl/sda to the MCU scl/sda pins and run firmware "example:oled-hello".

gndvccsclsda
HELLOWORLD
LCD 16×2
lcd1602

HD44780 16×2 character LCD, 4-bit mode. Pair with firmware "example:lcd-hello": D4–D7 = MCU d2–d5, e = d6, rs = d7. Arduino cloud compile provides LiquidCrystal_PCF8574 2.3.0 (`#include <LiquidCrystal_PCF8574.h>`), but treat it as compile-only: AVR I2C byte timing is not yet modeled, so a PCF8574 backpack may miss E strobes; direct parallel wiring is the accepted runtime path. The default backpack map is P0=RS, P2=E and P4–P7=D4–D7.

vccgndrsed4d5d6d7
OLED
OLED 1.3″
sh1106

SH1106 1.3" 128×64 OLED, I²C address 0x3C. Like the SSD1306 but page-addressed with a 2-column RAM offset: a correct SH1106 driver sets the column pointer to 2. Pins: gnd/vcc/scl/sda.

gndvccsclsda
OLED128²
OLED 1.5″ 128×128
sh1107

1.5″ 128×128 monochrome OLED (SH1107) on I²C at address 0x3D (so it coexists with a 0x3C SSD1306/SH1106). Page-addressed: 16 pages × 128 columns, no column offset; select page 0xB0+p, column via low nibble 0x00-0x0F + high 0x10-0x17, then write 128 data bytes. 0x20/0x21 are standalone addressing-mode commands (no argument, unlike the SSD1306). Init: 0xAE, config, 0xAF.

gndvccsclsda
LED Matrix 8×8
max7219

8×8 LED matrix driven by a MAX7219 over SPI. Pins: vcc/gnd/din/cs/clk. Clock 16-bit words MSB-first (register in high byte, data low byte); registers 1–8 are the 8 rows, 0x0C shutdown (send 1 for normal), 0x0F display-test. Use SoftSPI/bit-bang from MCU GPIOs. Powers up blank in shutdown; send 0x0C,0x01 first.

Powers up blank in shutdown; send 0x0C,0x01 before anything shows.
vccgnddincsclk
LED Matrix 32×8 (4-in-1)
max7219x4

32×8 LED matrix: four cascaded MAX7219s (FC16 4-in-1 bar) over SPI. Pins: vcc/gnd/din/cs/clk. Shift 4×16-bit words per CS-low window, MSB first: the FIRST word addresses the LEFTMOST 8×8 block; register 0x00 is a no-op filler. Registers 1–8 are rows, 0x0C shutdown (send 1 per chip to wake), 0x0F test. MicroPython: NO max7219 module on the bench (import fails) — shift the 16-bit words yourself (hardware machine.SPI(1) on the ESP32-C6/C3/S2/S3: din=g7, clk=g6 (S2/S3: pass sck/mosi pins explicitly); machine.SPI(2) on the classic ESP32: din=g23, clk=g18; machine.SoftSPI elsewhere) + a CS GPIO; Arduino: the allowlisted MAX7219 matrix library works.

vccgnddincsclk
LED Matrix 64×8 (8-in-1)
max7219x8

64×8 LED matrix: eight cascaded MAX7219s (8-in-1 bar) over SPI — same protocol as max7219x4 but 8×16-bit words per CS-low window (first word = leftmost block). Pins: vcc/gnd/din/cs/clk. Registers 1–8 are rows, 0x0C shutdown (send 1 per chip to wake), 0x0F test. MicroPython: NO max7219 module on the bench (import fails) — shift the words yourself (hardware machine.SPI(1) on the ESP32-C6/C3/S2/S3: din=g7, clk=g6 (S2/S3: pass sck/mosi pins explicitly); machine.SPI(2) on the classic ESP32: din=g23, clk=g18; machine.SoftSPI elsewhere) + a CS GPIO; Arduino: the allowlisted MAX7219 matrix library works. Wide enough for a readable scrolling ticker.

vccgnddincsclk
E-Ink 1.54″ 200×200
eink154

E-paper 1.54″ 200×200 (SSD1681), 4-wire SPI. Pins: vcc(3V3)/gnd/din/clk/cs/dc/rst/busy. Drive with SPI (hardware machine.SPI(1) on the ESP32-C6/C3/S2/S3: din=g7, clk=g6 (S2/S3: pass sck/mosi pins explicitly); machine.SPI(2) on the classic ESP32: din=g23, clk=g18; SoftSPI elsewhere) + GPIO for dc/cs/rst and poll busy (input): writes to RAM (0x24) show NOTHING until Master Activation (0x20) completes the selected refresh (~1.38 s full OTP at about 21 °C; poll BUSY). Standard init: rst pulse, 0x12 SW reset (wait BUSY low), 0x11 0x03 entry mode, 0x44/0x45 window, 0x4E/0x4F counters, stream 5000 bytes (MONO_HLSB, 1 = white), 0x22 0xF7, 0x20, wait at least 50 µs, then poll BUSY until low (BUSY rises about 33 µs after 0x20). The image persists with power removed.

GxEPD2 1.6.9 uses the owner-approved GPL-3.0 source/licence-note policy; its full init also sends the explicitly unmodeled commands listed here. On AVR use a small paged buffer, not a 5000-byte full frame.
RAM writes are invisible until Master Activation (0x20) completes.
At about 21 °C: full OTP ~1.38 s, partial OTP ~0.57 s. Only the two measured Waveshare custom LUTs are supported.
Unmodeled commands report warnings, including 0x01, 0x18, 0x3C, 0x37, 0x21, 0x10 and 0x0C.
The image survives power-off; clearing it requires another refresh.
vccgnddinclkcsdcrstbusy
vcc: 3.3 V supply
gnd: ground
din: SPI MOSI: pixel data and commands, MSB first
clk: SPI clock: data sampled on the rising edge while CS is low
cs: chip select, active low; frames each transaction
dc: data/command select: low = command byte, high = data bytes
rst: hardware reset, active low (hold ~10 ms at init)
busy: OUTPUT: high while a refresh is running; poll until low
E-Ink 2.13″ 250×122
eink213

E-paper 2.13″ 250×122 (SSD1680), same 8-pin SPI header and command set as eink154. Controller RAM is PORTRAIT 122×250 (16 bytes × 250 rows, 4000 bytes); the panel mounts landscape (RAM y runs along the long edge), so draw into a 128×250 MONO_HLSB framebuf and rotate your content 90° like real drivers do. The simulator approximates an unmeasured refresh via 0x20 as 1 s (BUSY high); the image persists unpowered.

GxEPD2 1.6.9 carries GPL-3.0 terms and uses the resolved-build source/licence-note policy.
RAM is portrait (16 bytes × 250 rows); the panel mounts landscape, so rotate your framebuffer like real drivers do.
Refresh (0x20) uses an unmeasured 1 s approximation with BUSY high; content persists without power.
vccgnddinclkcsdcrstbusy
TFT 1.8″ 160×128 (ST7735)
st7735

Color TFT 1.8″ 160×128 (ST7735), 4-wire SPI. Pins: vcc(3V3)/gnd/din/clk/cs/dc/rst. Unlike e-paper, pixels appear immediately. Set an address window with 0x2A CASET (xs_hi xs_lo xe_hi xe_lo) and 0x2B RASET (ys…), then stream RGB565 pixels (2 bytes, big-endian, 5-6-5) after 0x2C RAMWR; the counter wraps x then y across the window. 0x3A COLMOD selects the pixel format (0x05 = 16-bit), 0x36 MADCTL sets orientation. MicroPython: NO st7735 module on the bench (import fails) — send exactly this command set yourself; on the ESP32-C6/C3/S2/S3 use HARDWARE machine.SPI(1) (din=g7, clk=g6 — the C6/C3 port defaults; S2/S3 need them explicit: sck=Pin(6), mosi=Pin(7)) and on the classic ESP32 machine.SPI(2) (din=g23, clk=g18 — its defaults); frames stream at bus speed. Elsewhere machine.SoftSPI, with a GPIO for dc/cs/rst either way; Arduino: Adafruit_ST7735 (in the compile library set) works unmodified.

Pixels are RGB565 (2 bytes, big-endian) unless COLMOD (0x3A) selects 18-bit.
Always set the CASET/RASET window before a RAMWR burst; the counter wraps within it.
MADCTL (0x36) MV/MX/MY rotate and mirror — a landscape driver flips the axes.
vccgnddinclkcsdcrst
vcc: 3.3 V supply (also feeds the LED backlight on the module)
gnd: ground
din: SPI MOSI: pixel data and commands, MSB first
clk: SPI clock: data sampled on the rising edge while CS is low
cs: chip select, active low; frames each transaction
dc: data/command select: low = command byte, high = data bytes
rst: hardware reset, active low (hold ~10 ms at init)
TFT 2.8″ 240×320 (ST7789)
st7789

Color TFT 2.8″ 240×320 IPS (ST7789), 4-wire SPI — the same ST77xx command set as the ST7735 (CASET/RASET/RAMWR windows, RGB565 big-endian, MADCTL orientation, COLMOD pixel format) on a canvas with ~4.7× the pixels. Pins: vcc(3V3)/gnd/din/clk/cs/dc/rst. Arduino: Adafruit_ST7789 (in the compile library set) works unmodified. MicroPython: drive it with framebuf strips — on the ESP32-C6/C3/S2/S3 over hardware machine.SPI(1) (din=g7, clk=g6; S2/S3: pass the pins explicitly) or the classic ESP32 over machine.SPI(2) (din=g23, clk=g18), elsewhere over SoftSPI — a full 240×320 RGB565 frame is 150 KB, more than the heap wants in one piece.

A full-screen RGB565 buffer is 150 KB — render in horizontal strips (e.g. 240×40) and push each strip with its own CASET/RASET window.
Same ST77xx rules as the 1.8″: window before RAMWR, RGB565 big-endian, MADCTL for rotation.
The controller RAM is portrait 240×320; landscape drivers set MADCTL MV and swap the window axes.
vccgnddinclkcsdcrst
vcc: 3.3 V supply (also feeds the LED backlight on the module)
gnd: ground
din: SPI MOSI: pixel data and commands, MSB first
clk: SPI clock: data sampled on the rising edge while CS is low
cs: chip select, active low; frames each transaction
dc: data/command select: low = command byte, high = data bytes
rst: hardware reset, active low (hold ~10 ms at init)
Round IPS TFT 1.28″ 240×240 (GC9A01)
gc9a01

Round 1.28″ 240×240 IPS TFT LCD (GC9A01A), not OLED. Four-wire SPI with a separate D/C pin. The visible circle is inscribed in square 240×240 GRAM. Supported: hardware/software reset, sleep/display on-off, inversion, CASET/RASET/RAMWR, MADCTL orientation/BGR and RGB565/RGB666. Supports the ESP-IDF esp_lcd_gc9a01 2.0.4 init sequence exactly. Arduino/MicroPython drivers, including Adafruit_GC9A01A, are not supported yet; their different vendor commands/settings are refused. Other commands or undocumented settings raise a warning. There is no read-data pin. Supported firmware path: ESP32-S3, ESP-IDF only; wire DIN to G7 and CLK to G6. C3/C6 are not claimed. For a working project, open the Round eye example; do not generate a MicroPython script or Arduino sketch for this display.

This module model uses BGR=1 and INVON for ordinary colours. INVOFF complements the displayed colours without changing GRAM.
RGB565 is two bytes per pixel, most significant byte first. Draw in strips to avoid a large framebuffer.
Read commands, scrolling, partial/idle modes, memory-continue and alternate vendor init bytes are refused. Software reset preserves GRAM, MADCTL and pixel format; hardware reset also resets MADCTL and format.
The circle edge uses a pixel-centre rule. Analog gamma, scan timing and backlight brightness control are not simulated.
vccgnddinclkcsdcrst
vcc: 3.3 V supply; the module backlight is tied to this rail
gnd: ground
din: SPI MOSI, MSB first
clk: SPI clock, rising-edge samples
cs: active-low chip select; pauses preserve complete bytes
dc: low for commands, high for parameters and pixels
rst: active-low hardware reset; preserves GRAM
Thermal printer 58 mm
thermalprinter

58 mm TTL thermal receipt printer (the CSN-A2 / QR701 class), driven by ESC/POS bytes over a HARDWARE serial port. Pins rx, gnd, vcc — wire the MCU's UART TX pin to rx, share gnd, and give vcc a 5 V rail (below 4 V the module is off and hears nothing; real ones want 5-9 V and a supply that can deliver amps to the head). SUPPORTED BOARDS, and this is a hardware-serial-only part: Arduino Uno R3 / Nano / ATmega328P module — Serial, TX = d1; Arduino Mega — Serial(d1), Serial1(d18), Serial2(d16), Serial3(d14), any of them. Uno R4 uses physical Serial1 TX on d1: the adapter delivers completed, electrically validated 8N1 frames through the solved net. The Raspberry Pi Pico / Pico W hardware UARTs are wired too (UART0 TX = GP0/GP12/GP16/GP28, UART1 TX = GP4/GP8/GP20, routed by whichever pin the firmware muxes to the UART function), but MICROPYTHON CANNOT REACH THEM TODAY: constructing `machine.UART(...)` hangs the emulated Pico, because its UART model leaves the transmit interrupt permanently asserted once MicroPython enables it — nothing to do with the printer, and nothing a sketch can work around. Use an Uno, Nano or Mega for a printer project. NOT SUPPORTED AT ALL on the ESP32 boards or the Pico 2: their emulator core merges every UART with the USB console into one host stream with no per-port or per-pin identity, so there is nothing to route. SoftwareSerial / bit-banged UART cannot feed this printer on any board: it accepts only completed hardware-UART frames. (On the Uno R4 WiFi the official SoftwareSerial library does run and drives a real waveform on its TX pin, which another board's hardware UART can receive, but this printer part does not decode pin waveforms.) The printer does not check the baud rate. WHAT IT UNDERSTANDS: printable ASCII 0x20-0x7E; LF (0x0A) prints the line and feeds; CR ignored; HT tabs to 4-column stops; ESC @ initialize; ESC ! n print mode (bit 3 emphasized, bit 4 double height, bit 5 double width); GS ! n character size (low nibble height, high nibble width — anything above ×1 reads as doubled); ESC a n justify (0 left, 1 centre, 2 right); ESC d n feed n lines; ESC J n feed n dots (24 dots = one line); ESC 2 / ESC 3 n line spacing (accepted, no visual effect). 32 COLUMNS of font A across the 384-dot head, 16 when double width is on; longer text wraps. Everything else is consumed and not drawn — including underline, inverse, the raster bitmap commands (ESC *, GS v 0, DC2 *), barcodes (GS k, both the NUL-terminated format A and the length-prefixed format B) and the GS ( function blocks QR codes are built from, whose binary payloads are all swallowed by their own length rules so they never land on the paper as garbage and never knock the parser out of step. POWER: everything except the paper already through the slot is volatile — a module that loses its 5 V rail comes back with an empty buffer AND the power-on formatting, exactly as if it had just been sent ESC @, so re-send your style after a brown-out. PACING: the head prints about 4 lines a second and feeds blank paper about 50, in simulated time, so a burst of println()s really does crawl out of the slot; the canvas strip shows the last 12 lines and keeps 200. There is no DTR handshake, so a sketch that prints faster than the head can keep up loses lines exactly like the real module does. The printer never talks back: paper-out status, GS r and DTR are not modelled. Firmware to try: "example:thermal-printer" on an Uno/Nano/328P, or "example:mega-thermal-printer" on a Mega (that one prints out of Serial1/d18 while narrating on Serial).

Arduino cloud compile provides Adafruit Thermal Printer Library 1.4.1 (`#include <Adafruit_Thermal.h>`). Pass a hardware serial Stream; bitmap/barcode, status and DTR remain unsupported.
Every byte still reaches the Serial monitor too — a hardware TX pin drives both, so a receipt looks like control-character noise in the terminal.
A line is not on the paper the moment you print it: the head takes ~250 ms per line.
rxgndvcc
rx: Serial in, TTL. Wire the MCU's UART TX pin here.
gnd: Ground — share it with the MCU.
vcc: 5 V. Real modules want 5-9 V and an amp or two for the head; the model only needs a live 5 V rail.

Sensors

SEN55
sen55

I²C air-quality sensor (Sensirion command set). Wire sda/scl to the MCU sda/scl pins and run firmware "example:i2c-sen55".

vddgndsdasclsel
BME280
bme280

Bosch BME280 environment sensor, real I²C protocol at 0x76 (chip-id 0xD0 reads 0x60; calibration and compensation modeled). Arduino: the allowlisted BME280 library works. MicroPython: NO bme280 module on the bench and the raw compensation math is substantial — for a simple temperature readout prefer the TMP36 (tempsensor) on an ADC pin. Reads return the temperature/humidity/pressure configured in the Inspector. Pins: gnd/vcc(3V3)/scl/sda.

gndvccsclsda
MPU-6050
mpu6050

MPU-6050 6-axis IMU, real I²C protocol at 0x68. Arduino: standard MPU6050 libraries work. MicroPython: NO driver module — use raw registers: wake it by writing 0x00 to reg 0x6B, WHO_AM_I at 0x75 reads 0x68, accel X/Y/Z at 0x3B–0x40 (big-endian int16, 16384 LSB/g at the ±2g default). Reads return the acceleration/rotation configured in the Inspector. Pins: gnd/vcc(3V3)/scl/sda.

gndvccsclsda
TCS34725 color sensor
tcs34725

AMS TCS34725 RGB colour sensor, real I²C protocol at the fixed address 0x29. EVERY register access must set the command bit: send 0x80 | register (0xA0 | register for auto-increment across a burst; this model treats repeated-byte and auto-increment the same, and accepts the 0xE6 clear-interrupt special function as a no-op). Registers: 0x00 ENABLE (PON bit0, AEN bit1), 0x01 ATIME (integration = (256 − ATIME) × 2.4 ms), 0x0F CONTROL AGAIN[1:0] → 1/4/16/60×, 0x12 ID reads 0x44, 0x13 STATUS AVALID bit0 (set once PON+AEN have been on for one integration time), 0x14-0x1B CDATA/RDATA/GDATA/BDATA as 16-bit LITTLE-endian pairs. The colour it sees is props.color ('#rrggbb', editable live in the Inspector). Counts are the sRGB-linearised channels scaled by integration time and gain, normalised so one 2.4 ms cycle at 1× gain on pure white ≈ 1000 counts per channel; the clear channel is 0.30R + 0.59G + 0.11B plus a small dark offset. Counts saturate at min(1024 × cycles, 65535). ATIME resets to 0xFF, which is a single 2.4 ms integration and therefore tiny counts — write a lower ATIME (0xEB ≈ 50 ms) for usable numbers. MicroPython: NO tcs34725 driver module — `i.readfrom_mem(0x29, 0x92, 1)` reads the ID, `i.writeto_mem(0x29, 0x80, b"\x03")` enables it. Pins: gnd/vcc(3V3)/scl/sda/led (the led pin is decorative — the reading does not depend on it). Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

Arduino cloud compile provides Adafruit TCS34725 1.4.4 (`#include <Adafruit_TCS34725.h>`); use the ID, integration, gain and RGB/clear paths. Interrupt thresholds are not modeled.
Forget the 0x80 command bit and the part ignores the whole transaction, exactly like the real one — read the ID at 0x92, not 0x12.
ATIME defaults to 0xFF, which is a single 2.4 ms integration and therefore very small counts; write a lower ATIME (0xEB ≈ 50 ms) for usable numbers.
gndvccsclsdaled
BH1750 light sensor
bh1750

ROHM BH1750FVI ambient-light sensor, real I²C protocol. props.addr picks 0x23 (default, ADDR low) or 0x5C; the addr PIN is decorative — the prop is what the bus sees. Arduino cloud compile provides BH1750 1.3.0 (`#include <BH1750.h>`). Its begin() address argument defaults to 0x23 and overrides the constructor address, so for a part at 0x5C pass it to begin(): `light.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x5C)`. props.lux (0–100000) is the illuminance the part measures, editable live in the Inspector. No register file: every write is an OPCODE — 0x00 power down, 0x01 power on, 0x07 reset the data register, 0x10 continuous H-res (1 lx, 120 ms), 0x11 continuous H-res2 (0.5 lx), 0x13 continuous L-res (4 lx, 16 ms), 0x20/0x21/0x23 the one-time variants (they return to power-down the moment the MEASUREMENT finishes, not when you read it — the data register then holds that result for as many reads as you like, and a light change after the window does not alter it; send the opcode again for a fresh reading), and MTreg as the pair 0x40|(MT>>5) then 0x60|(MT&0x1F) (31–254, default 69, scales both the count and the integration time). A read returns 2 bytes BIG-endian; lux = raw / 1.2 (halve again in H-res2). Data is 0 until the mode's integration time has elapsed. MicroPython: NO bh1750 driver module on the bench — use raw I²C (`i.writeto(0x23, b"\x10")`, wait 180 ms, `i.readfrom(0x23, 2)`), or paste a driver into the project files. Pins: gnd/vcc(3V3)/scl/sda/addr. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

gndvccsclsdaaddr
T°
Temp (TMP36)
tempsensor

TMP36: out = 0.5 V + 10 mV/°C. props.tempC is the simulated temperature (user slider).

vccoutgnd
Photoresistor
photoresistor

LDR: ~1 kΩ bright to ~1 MΩ dark. props.lightLevel 0–1 (user slider). Use in a divider.

ab
HC-SR04
hcsr04

Ultrasonic ranger: ≥10 µs pulse on trig → echo high 58 µs/cm. props.distanceCm 2–200 (user slider). Pair with firmware "example:ultrasonic" (trig=d9, echo=d8).

vcctrigechognd
DHT11
dht11

Single-wire temp/humidity sensor. props.tempC, props.humidity (user sliders). ARDUINO ONLY: pair with firmware "example:dht11" (data=d2). MicroPython's dht module cannot read this part on the bench (measure() raises ETIMEDOUT) — for a MicroPython temperature project use the TMP36 (tempsensor) on an ADC pin instead.

vccdatagnd
DS18B20 (1-Wire)
ds18b20

Maxim DS18B20 1-Wire digital thermometer in a TO-92 (pins gnd, dq, vcc — flat face toward you, left to right). props.tempC is the simulated temperature, −55 to +125 °C (user slider), and it speaks the REAL Maxim protocol on dq: reset/presence, LSB-first time slots, READ/MATCH/SKIP/SEARCH ROM, CONVERT T, READ/WRITE SCRATCHPAD, COPY SCRATCHPAD, RECALL E² and CRC-8. TH/TL and the resolution live in the VOLATILE scratchpad: WRITE SCRATCHPAD (0x4E) alone is lost on the next power cycle or bench Reset, which brings back whatever the EEPROM holds (the factory 75 °C / 70 °C / 12-bit until you store something). COPY SCRATCHPAD (0x48) stores them and RECALL E² (0xB8) loads them back on demand; both are instantaneous here, so the read slots that report their progress answer 1 straight away. Wire vcc — parasite power is not modeled, and READ POWER SUPPLY answers "externally powered". WIRING: a 1-Wire bus needs a pull-up on dq, and real hardware needs an external 4.7 kΩ from dq to vcc; this part stamps that resistor internally so a bare three-wire hookup already works on the bench (add the resistor anyway if you are drawing the circuit you intend to build). Several sensors share one dq wire and are enumerated by SEARCH ROM; each gets a stable ROM code from its component id. SUPPORTED: the bundled AVR firmware "example:ds18b20" (dq=d2), and MicroPython on the Pico 2 with the frozen drivers — `import onewire, ds18x20; ow=onewire.OneWire(machine.Pin(2)); ds=ds18x20.DS18X20(ow); r=ow.scan(); ds.convert_temp(); time.sleep_ms(800); ds.read_temp(r[0])`. NOT SUPPORTED from MicroPython on the ESP32 boards: their emulated pads have no open-drain driver, so `Pin.OPEN_DRAIN` drives the wire high instead of releasing it, the frozen onewire driver never sees a presence pulse and ow.scan() comes back empty — for an ESP32 temperature project use the TMP36 (tempsensor) on an ADC pin instead. Reading 85.0 °C means the scratchpad's power-on value: run CONVERT T and wait the conversion time (750 ms at the default 12-bit, then 375/187.5/93.75 ms for 11/10/9-bit set through the config register) before reading.

Arduino cloud compile provides OneWire 2.3.8, DallasTemperature 4.0.6 and DS18B20 1.0.0 (`OneWire.h`, `DallasTemperature.h`, `DS18B20.h`). These drivers require external sensor power; newer ESP32 C5/C6/H2/P4 paths are not admitted by this recipe.
A conversion already in flight keeps the temperature it started with; edit the slider and convert again to see the new value.
The 9/10/11-bit modes really do zero the low bits of the temperature register, exactly like the silicon.
gnddqvcc
gnd: Ground. Left-hand leg with the flat face toward you.
dq: The 1-Wire bus: open-drain data, and the pull-up lives here.
vcc: 3.0–5.5 V. Must be wired; parasite power off dq is not modeled.
IR receiver (TSOP38238)
irreceiver

TSOP38238-style 38 kHz infrared receiver (pins out, gnd, vcc — the real part's own order, lens facing you). It hands over the DEMODULATED envelope, not the carrier: OUT idles HIGH and goes LOW for as long as a burst is arriving, so a decoder just measures pulse widths. Select the part and the Inspector shows a working 21-key "Car MP3" kit remote — press a button to send a real NEC frame, hold one to send NEC repeat bursts every 110 ms until you let go. NEC: a 9 ms mark + 4.5 ms space leader, then 32 bits LSB-first (address, ~address, command, ~command) where every bit is a 562.5 µs mark plus a 562.5 µs space for 0 or a 1687.5 µs space for 1, then a final 562.5 µs mark — 68 ms per frame. A repeat burst is 9 ms + 2.25 ms + 562.5 µs, and that halved space is how you tell it from a new key. props.addr is the address the remote sends (default 0x00, what these kit remotes use). KIT REMOTE CODES: CH-=0x45 CH=0x46 CH+=0x47 PREV=0x44 NEXT=0x40 PLAY/PAUSE=0x43 VOL-=0x07 VOL+=0x15 EQ=0x09 0=0x16 100+=0x19 200+=0x0D 1=0x0C 2=0x18 3=0x5E 4=0x08 5=0x1C 6=0x5A 7=0x42 8=0x52 9=0x4A. SUPPORTED both ways: the bundled AVR firmware "example:ir-receiver" (out=d2) prints "IR ADDR=0x00 CMD=0x45" per key and "IR REPEAT" while one is held; and MicroPython on any board with nothing but the stock `machine.time_pulse_us` — `p=Pin(n,Pin.IN); lead=time_pulse_us(p,0,2000000); sp=time_pulse_us(p,1,20000); b=[(time_pulse_us(p,0,20000),time_pulse_us(p,1,20000)) for _ in range(32)]` then read bit i as `b[i][1]>1000` (lead≈9000 and sp≈4500 mean a key; sp≈2250 means a repeat). There is no `ir_rx` module on the images (probed: ImportError), and none is needed. NOT MODELED: transmitting. An MCU cannot bit-bang an IR LED here — a 38 kHz carrier is 13 µs per half period, below what the simulator samples GPIO at — so the on-screen remote is the only source of infrared on the bench.

Arduino cloud compile provides IRsmallDecoder 1.3.0 (`IRsmallDecoder.h`) and IRremote 4.7.1 (`IRremote.hpp`). Select NEC reception; IRremote links GPL-3.0-or-later headers and gets a source/licence note. Neither addition enables IR transmission.
OUT is active LOW: no button pressed means a steady HIGH, and a key press is a run of LOW pulses.
Real remotes repeat every 108–110 ms; this one uses 110 ms, the figure Arduino-IRremote pins.
The same codes carry different legends on different kit remotes — 0x45 is CH- on the "Car MP3" remote and POWER on the Elegoo one.
OUT is driven both ways here. A real TSOP382 pulls down and idles high through an internal ~30 kΩ, so two of them can share one wire; two of these cannot.
outgndvcc
out: Demodulated output, ACTIVE LOW, idles high. Wire to any input pin.
gnd: Ground. Middle leg, as on the real TSOP38238.
vcc: 2.5–5.5 V. Below 2.5 V the module drives nothing at all.
PIR Motion
pir

PIR motion sensor (HC-SR501). Pins: vcc/out/gnd. OUT is a ~3.3 V push-pull logic output that pulses high for props.holdSec seconds when motion is triggered (Inspector "Trigger motion" button).

vccoutgnd
MQ-2 Gas Sensor
mq2

MQ-2 gas/smoke sensor (LM393 breakout). Pins: vcc/gnd/aout/dout. aout ≈ 0.4 V clean air → 3.75 V dense smoke (ADC-readable); dout is push-pull and drops LOW when gas exceeds props.threshold. The heater warms up ~5 s after power (readings run high until settled; poll like real firmware does). props.gas 0–1 and props.threshold 0–1 (Inspector sliders).

No alarm and inflated readings during the ~5 s heater warm-up; poll before trusting, like real firmware.
DOUT is active-LOW (stock LM393 boards light their LED on low).
vccgndaoutdout
vcc: 5 V supply (the heater is the real load)
gnd: ground
aout: analog gas level: ~0.4 V clean air → ~3.75 V dense smoke
dout: OUTPUT: comparator alarm, LOW when gas exceeds the threshold
Soil Moisture
soilmoisture

Analog soil-moisture / water-level probe. Pins: vcc/gnd/aout. aout is an absolute analog voltage (~2.5 V dry → ~0.2 V saturated) an ADC reads. props.moisture 0–1 (Inspector slider).

vccgndaout
vcc: ≥2.7 V supply
gnd: ground
aout: analog level: ~2.5 V dry → ~0.2 V saturated

Smart home · Matter & Thread

Matter Controller
mattercontroller

Matter controller: a sealed ESP32-S3 running the canonical ESP-Matter commissioner and Breadboard BBM1 command/event firmware. Wire gnd + vcc (5 V). It commissions Matter bulbs through real CHIPoBLE/PASE, routes operational traffic through a Thread Border Router, and invokes real CASE/OnOff commands. Use its Inspector for guided actions or the Serial panel for the preserved manual shell. Test credentials only; no certification or physical-fabric interoperability claim.

gndvcc
Matter Bulb
matterbulb

Matter-over-Thread smart bulb: a sealed C6 running the canonical ESP-Matter OnOff endpoint with the structured BBE1 reset lifecycle. Wire gnd + vcc (5 V) only; the bulb advertises over CHIPoBLE for the native commissioner and joins the virtual Thread fabric after commissioning. Its real Matter OnOff command drives GPIO8/WS2812 and the rendered lamp follows. Test credentials are disclosed in the firmware provenance record; this is not a certification or physical-fabric interoperability claim.

gndvcc
Matter Color Bulb
mattercolorbulb

Matter-over-Thread color bulb: a sealed C6 running the canonical ESP-Matter extended-color-light endpoint with real OnOff/Level/Color clusters and the structured BBE1 reset lifecycle. Wire gnd + vcc (5 V). Real MoveToLevel/MoveToHueAndSaturation commands over CASE drive its internal GPIO8/WS2812 and the rendered lamp follows. Test credentials only; no certification or physical-fabric interoperability claim.

gndvcc
Matter Plug
matterplug

Matter-over-Thread smart plug: a sealed C6 running the canonical ESP-Matter on/off-plug-in-unit endpoint with the structured BBE1 reset lifecycle. Wire gnd + vcc (5 V); vout/gnd2 are the switched outlet — the firmware's real GPIO8 relay level ties vout to vcc when its Matter OnOff state is on, powering whatever is wired downstream. Test credentials only; no certification or physical-fabric interoperability claim.

gndvccvoutgnd2
Matter Contact Sensor
mattercontact

Matter-over-Thread contact sensor: a sealed C6 running the canonical ESP-Matter contact-sensor endpoint with the structured BBE1 reset lifecycle. Wire gnd + vcc (5 V); c1/c2 are the contact terminals — short them = CLOSED. The controller reads the authoritative native Boolean State attribute (cluster 69) over real CASE; the app never invents the value. Test credentials only; no certification or physical-fabric interoperability claim.

gndvccc1c2
Matter Temp Sensor
mattertempsensor

Matter-over-Thread temperature sensor: a sealed C6 running the canonical ESP-Matter temperature-sensor endpoint with the structured BBE1 reset lifecycle. Wire gnd + vcc (5 V); the probe pin is its ADC input — 0..3.3 V maps to -10..+50 °C. The controller reads the authoritative native Temperature Measurement attribute (cluster 1026, centi-°C) over real CASE. Test credentials only; no certification or physical-fabric interoperability claim.

gndvccprobe
Thread Control Button
threadbutton

Powered wireless control surface for a Matter controller. Wire gnd + vcc (5 V); its green lamp follows the solved supply voltage and an unpowered button cannot send a command. Set props.matterTarget to the component id of a Matter bulb, color bulb, or plug. A press is accepted only after that endpoint is commissioned; it enters the real controller firmware through BBM1 and the endpoint changes only after the Matter OnOff command succeeds over CASE/Thread. This control does not claim a separate emulated radio or Generic Switch endpoint.

gndvcc
Thread Sensor Node
threadsensor

Thread sensor node: a sealed C6 running OpenThread. Wire gnd + vcc (5 V). It attaches to the Thread hub's network as a child (same fixed dataset) and reports its temperature over UDP to ff03::1:12345 every 5 s — watch the hub's serial tab and the 802.15.4 frames in the sniffer.

gndvcc

Smart home · Zigbee

Zigbee Bulb
zigbeebulb

Zigbee smart bulb: a real emulated ESP32-C6 running genuine esp-zigbee light firmware inside a lamp. Wire gnd + vcc (5 V) only; the radio joins the bench's shared 802.15.4 air. Pair it with an esp32c6 running the Zigbee coordinator/switch firmware: it joins, binds, and real ZCL Toggle frames light it. Click it for the join state.

gndvcc
Zigbee Plug
zigbeeplug

Zigbee smart plug: the bulb's sibling appliance — the hidden C6 decides on/off and the plug SWITCHES ITS OUTLET. Wire gnd + vcc (5 V) to power it; vout carries vcc only while the ZCL state is on (gnd2 = outlet ground), so a lamp or circuit wired to vout/gnd2 powers up when a coordinator toggles it. Click it for the join + outlet state.

gndvccvoutgnd2
Zigbee Color Bulb
zbcolorbulb

Zigbee color bulb: like zigbeebulb but the sealed C6 runs color-dimmable-light firmware — ZCL On/Off, Level and Color commands tint the glass (full RGB). Wire gnd + vcc (5 V) only. Pair with a coordinator that sends color (the color remote firmware auto-cycles a wheel). Click it for join state and current color.

gndvcc
Zigbee Contact Sensor
zbcontact

Zigbee contact sensor (door/window): a sealed C6 running esp-zigbee IAS-zone contact firmware. Wire gnd + vcc (5 V) to power it; c1/c2 are the contact terminals — short them (a wire, switch or button) = door CLOSED, open = door OPEN. Each change reports a genuine IAS zone status to the coordinator over the air. Click it for join + contact state.

gndvccc1c2
Zigbee Temp Sensor
zbtempsensor

Zigbee temperature sensor: a sealed C6 running esp-zigbee temperature firmware. Wire gnd + vcc (5 V); the probe pin is its ADC input — 0..3.3 V maps to -10..+50 °C (a trim pot wiper sweeps it). Reports ride the standard temperature-measurement cluster to a bound thermostat hub. Click it for join state + the live probe reading.

gndvccprobe
Zigbee Smart Button
zbbutton

Zigbee smart button: a sealed COORDINATOR puck (esp-zigbee switch firmware). Wire gnd + vcc (5 V). It forms and opens the network; bulbs/plugs join and bind to it. CLICK AND HOLD IT briefly to press the internal button — a real ZCL Toggle to every bound light. Click (select) it for network state.

gndvcc

Modules

DS3231 RTC
ds3231

DS3231 real-time clock, I²C at 0x68 (BCD time registers). Time advances with simulation time from props.baseTime (ISO string), so it is deterministic. Pins: gnd/vcc(3V3)/scl/sda.

gndvccsclsda
ADS1115 16-bit ADC
ads1115

TI ADS1115 16-bit 4-channel ADC, real I²C register protocol. props.addr picks 0x48 (default) / 0x49 / 0x4A / 0x4B; the ADDR PIN is decorative — the prop is what the bus sees. Arduino cloud compile provides Adafruit ADS1X15 2.6.2 (`#include <Adafruit_ADS1X15.h>`, `Adafruit_ADS1115 ads; ads.begin(0x48)`). Four 16-bit BIG-endian registers behind a pointer byte: 0x00 conversion (read-only), 0x01 config (reset 0x8583), 0x02 Lo_thresh (0x8000), 0x03 Hi_thresh (0x7FFF). Config fields: OS bit15 (write 1 = start a single conversion; reads 0 only while one is in flight), MUX[14:12] 000 A0-A1 / 001 A0-A3 / 010 A1-A3 / 011 A2-A3 / 100 A0-GND / 101 A1-GND / 110 A2-GND / 111 A3-GND, PGA[11:9] full scale ±6.144/4.096/2.048(default)/1.024/0.512/0.256 V, MODE bit8 (1 = single-shot, the default), DR[7:5] 8/16/32/64/128(default)/250/475/860 SPS. The conversion samples the SOLVED voltages on a0-a3 and returns round(V/FS × 32767) as two's complement, clamped at the rails. Single-shot results become readable 1/DR seconds later in sim time. A conversion is a WINDOW: the MUX and PGA in force when it starts are the ones the result comes back through, and the value is taken when the window closes, so reading late reports what the part measured rather than what the net carries now. Config writes therefore land on the NEXT conversion — an OS=1 write while one is in flight has no effect (it neither restarts nor shortens it), and in continuous mode a channel change shows up one full period later, so throw the first sample after a MUX change away exactly as you would on hardware. MicroPython: NO ads1115 driver module — `i.writeto(0x48, b"\x01\xc5\x83")`, wait, then `i.readfrom_mem(0x48, 0x00, 2)`. Pins: gnd/vcc(3V3)/scl/sda/addr on the anchor row, a0-a3 across the channel — like the DIP ICs it MUST STRADDLE THE CHANNEL, so anchor it on row e and the a0-a3 pins land on row f. Anchored anywhere else the two rows share a strip and every input shorts to a bus pin. The comparator bits (COMP_MODE/POL/LAT/QUE) are stored and read back but inert, and there is no ALERT/RDY pin — poll the OS bit instead. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

The comparator bits (COMP_MODE/POL/LAT/QUE) are stored and read back but do nothing, and the ALERT/RDY pin is not on the part — poll the OS bit instead.
gndvccsclsdaaddra0a1a2a3
MCP4725 12-bit DAC
mcp4725

Microchip MCP4725 12-bit DAC with EEPROM, real I²C write/read framing. props.addr picks 0x60 (default) through 0x67. Arduino cloud compile provides Adafruit MCP4725 2.0.2 (`#include <Adafruit_MCP4725.h>`); its begin() defaults to 0x62, so pass the part's address: `dac.begin(0x60)`. Fast write: two bytes [0 0 PD1 PD0 D11..D8][D7..D0]. Write DAC: three bytes [0x40|PD<<1][D11..D4][D3..D0<<4]; 0x60 instead of 0x40 also writes EEPROM (a real 50 ms cycle during which writes are NACKed and the RDY status bit reads 0). A read returns 5 bytes: [RDY<<7 | POR<<6 | PD<<1][DAC D11..D4][D3..D0<<4][PD<<5 | EEPROM D11..D8][EEPROM D7..D0]. OUT drives Vout = VDD × D/4096 through a low-impedance buffered output; power-down modes 01/10/11 disconnect it and leave a 1 kΩ / 100 kΩ / 500 kΩ pull-down to GND. At power-on the DAC loads the EEPROM value (0x800, mid-scale). MicroPython: NO mcp4725 driver module — `i.writeto(0x60, bytes([0x0C, 0x00]))` sets three-quarter scale. Pins: gnd/vcc(3V3)/scl/sda/out. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

gndvccsclsdaout
PCF8574 I/O expander
pcf8574

NXP PCF8574 8-bit quasi-bidirectional I/O expander, real I²C protocol. props.addr picks 0x20 (default) through 0x27. There is NO register pointer: one written byte sets the output latch, one read byte returns the LEVELS ON THE PINS. A latch bit of 0 drives a strong low; a latch bit of 1 leaves only the ~100 µA pull-up, so an external driver or pull-down wins and the read reports it — that is how you read inputs (write 1s to the input bits first). Power-on latch is 0xFF. INT is open drain: it pulls low when a pin level differs from the levels captured at the last read/write, and releases on the next read/write — give it an external pull-up. MicroPython: NO pcf8574 driver module — `i.writeto(0x20, b"\xff")` then `i.readfrom(0x20, 1)[0]`. Pins: gnd/vcc(3V3)/scl/sda/int on the anchor row, p0-p7 across the channel — it MUST STRADDLE THE CHANNEL, so anchor it on row e and the p0-p7 pins land on row f. Anchored anywhere else the two rows share a strip and the port shorts to the bus pins. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

Arduino cloud compile provides Adafruit PCF8574 1.1.2 (`#include <Adafruit_PCF8574.h>`); choose the PCF8574 API, not PCF8575.
A pin only reads back the outside world if its latch bit is 1 — a 0 bit is a hard low the part itself is driving.
The pins move on the solve AFTER the latch write, so read them at least one sim step later (a MicroPython sleep_ms(1) is plenty).
This is the PCF8574, not the PCF8574A; the A part's 0x38-0x3F address range is a different component and is not modeled.
gndvccsclsdaintp0p1p2p3p4p5p6p7
INA219 current monitor
ina219

TI INA219 current/power monitor, real I²C register protocol. props.addr picks 0x40 (default) through 0x4F. Its 0.1 Ω shunt is a REAL element between vinp and vinm, so put the supply on vinp and the load on vinm and the part measures the current the solver actually computes. Six 16-bit BIG-endian registers behind a pointer byte: 0x00 config (reset 0x399F), 0x01 shunt voltage (signed, 10 µV/LSB), 0x02 bus voltage (value << 3, bit1 CNVR always ready, bit0 OVF; measured from vinm to GND), 0x03 power, 0x04 current = shunt × calibration / 4096, 0x05 calibration. The config fields that change what you read are real: bit 15 RST is a power-on reset that self-clears (config reads back 0x399F, calibration back to 0), bit 13 BRNG clamps the bus register to 16 V (4000 LSB) or 32 V (8000 LSB), and bits 12:11 PGA clamp the shunt register to ±40/80/160/320 mV (±4000/8000/16000/32000 LSB) with the datasheet's sign extension on the negative rail — pick a range that fits your shunt drop or the reading rails. OVF (bus bit 0) is the math-overflow flag: it means shunt × calibration / 4096 left the 16-bit register, so the current and power values are rails rather than measurements. The ADC/averaging fields are stored and read back but do not change the reading. Write calibration FIRST: with 0 the current and power registers read 0, exactly like the real part. For the 0.1 Ω shunt, calibration 4096 gives a 100 µA current LSB. MicroPython: NO ina219 driver module — write 0x05 then read 0x04. Pins: gnd/vcc(3V3)/scl/sda on the anchor row, vinp/vinm across the channel — it MUST STRADDLE THE CHANNEL, so anchor it on row e and vinp/vinm land on row f. Anchored anywhere else the two rows share a strip and the shunt shorts to the bus pins. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

Arduino cloud compile provides Adafruit INA219 1.2.3 (`#include <Adafruit_INA219.h>`). Use the modeled 0.1 ohm shunt and a calibration appropriate to the expected load.
Current and power read 0 until you write the calibration register — that is the real chip's behavior, not a bug.
gndvccsclsdavinpvinm
32K
AT24C32 EEPROM
at24c32

Atmel AT24C32 4 KB I²C EEPROM (the second chip on most DS3231 modules), real protocol. props.addr picks 0x50 (default) through 0x57. Two address bytes (12-bit, big-endian) then up to 32 data bytes; writes wrap INSIDE the 32-byte page they started in. The 10 ms internal write cycle is modeled: the part NACKs its own address until it finishes, so ACK polling works exactly as the datasheet describes. Reads are sequential from the address counter and roll over at 4096. A fresh part reads 0xFF everywhere; contents survive a board Reset (real EEPROM) but are NOT saved into the document, and editing the wiring rebuilds the part back to all-0xFF. MicroPython: raw I²C is the normal way — `i.writeto_mem(0x50, 0x0010, b"hi", addrsize=16)`, wait 10 ms, `i.readfrom_mem(0x50, 0x0010, 2, addrsize=16)`. Arduino cloud compile provides I2C_EEPROM 1.9.4 (`#include <I2C_eeprom.h>`): construct `I2C_eeprom(0x50, 4096)` and call `setExtraWriteCycleTime(5)`, because the library's default 5 ms write poll is shorter than the modeled 10 ms write cycle. Pins: gnd/vcc(3V3)/scl/sda. Wire scl/sda to the board's FIXED I²C pins: esp32c3/s2/s3 SDA=g8 SCL=g9, classic esp32 SDA=g21 SCL=g22, esp32c6 SDA=g23 SCL=g22, Pico/Pico 2 via the I2C0/1 mux (e.g. sda=GP4, scl=GP5).

Arduino cloud compile provides I2C_EEPROM 1.9.4 (`#include <I2C_eeprom.h>`). Construct I2C_eeprom(0x50, 4096) and call setExtraWriteCycleTime(5) to cover the modeled 10 ms write cycle; page-split writes and busy polling are required.
Contents are non-volatile within one loaded circuit — a board Reset keeps them — but they are NOT saved into the document, and editing the wiring rebuilds the part back to all-0xFF.
A write of more than 32 bytes wraps within the page and overwrites the start of the same transaction, like the real chip; write a page at a time.
gndvccsclsda
microSD card
microsd

64 MB microSD card on a 6-pin SPI breakout (gnd, vcc, cs, sck, mosi, miso). HARDWARE SPI ONLY: on the Uno wire sck=d13, mosi=d11, miso=d12 (cs = any GPIO, d10 by convention); on the Pi Pico or Pico 2 default SPI0 route wire sck=GP18, mosi=GP19, miso=GP16 (cs = any GPIO, GP17 by convention); Pico 2 also supports live valid RP2350 FUNCSEL routes, including SPI1 sck=GP26/mosi=GP27/miso=GP28; on the ESP32 C6/C3/S2/S3 wire sck=g6, mosi=g7, miso=g2 (cs = any GPIO; MicroPython SPI(1) — the port defaults on C6/C3; on S2/S3 pass them explicitly: SPI(1, sck=Pin(6), mosi=Pin(7), miso=Pin(2))); on the classic ESP32 wire sck=g18, mosi=g23, miso=g19 (MicroPython SPI(2) — the VSPI defaults). The card ships pre-formatted FAT16, so Arduino sketches and supported MicroPython ports can mount it. Arduino on AVR boards (Uno, Mega, Nano) and the Uno R4: both SD 1.3.0 (#include <SD.h>) and SdFat 2.3.0 (#include <SdFat.h>, SdFat sd; sd.begin(cs)) work. MIT SdFat is recommended for closed-source firmware and remains the example default. Firmware built with SD 1.3.0 carries GPL-3.0 terms (source and licence: https://github.com/arduino-libraries/SD/tree/a3866205cf9af4eea3e10dcdc5ac2c713f293337). Arduino on ESP32 boards: SD.h works (the ESP32 core's own SD library) — on C6/C3/S2/S3 call SPI.begin(6, 2, 7) before SD.begin(cs); it answers the full SPI-mode command set (CMD0/8/55+ACMD41/58, CMD17/18/24/25) with real CRCs. Pico 2 verifies the short CMD0/CMD8/ACMD41/CMD58 control path plus a stock 64-byte full-duplex transfer through its DMA-backed SPI path; a complete Pico 2 filesystem mount remains outside the acceptance golden. Contents persist across power cycles and resets within the session; a page reload starts from a fresh formatted card. Card contents can be SEEDED from the document: props.files is a JSON manifest of up to 16 {"name","ref"} entries — name is an 8.3 file name (A–Z 0–9 _ only, max 8 chars + optional 3-char extension), ref is "asset:/firmware/<file>" (bundled) or "idb:<sha256>:<name>:<len>" (user upload); REFS ONLY, never inline bytes — and the engine writes those files into the FAT16 image at boot. The bundled photo assets asset:/firmware/photo1.565 … photo3.565 are 160×128 raw .565 images (u16 LE width + u16 LE height header, then RGB565 big-endian pixels — streams straight into an ST77xx RAMWR window; users add their own via the Inspector's Card contents panel, which converts images to .565/.o64 on upload — and video clips or animated GIFs via "Add video…", stored as a .565 stream (8-byte header: u16 LE width, height, fps, frame count; then concatenated RGB565 frames) that the example script plays paced at its header fps). See the "microSD photo frame" example for the full card→TFT pipeline.

Uno R4 uses SPI0 on D13 SCK, D11 MOSI and D12 MISO with D10 GPIO chip select. Its verified gallery uses MIT SdFat 2.3.0 and the real 3.3 V rail. This byte-level seam proves SD initialization and block reads/writes, not analyzer-accurate SPI waveforms.
Every ESP32 variant's hardware SPI master is emulated (byte-level seam): GPSPI2 on C6/C3/S2/S3, SPI3/VSPI on the classic. SoftSPI reads are still not modeled anywhere (inputs freeze per analog step — same class of limit as SoftI2C) — use the hardware bus.
Pico 2 SPI0/1 is also a byte-level hardware seam with live FUNCSEL routing. Stock MicroPython transfers at and above its 32-byte DMA threshold use the modeled two-channel DMA/DREQ path through the real TX/RX FIFOs; a 64-byte full-duplex transfer is verified.
Wiring off the hardware-SPI pins means the card is never attached — like an I2C device on the wrong pins, the bus scan simply finds nothing.
MicroPython has NO frozen sdcard module: instantiate the ~40-line SPI driver from the "microSD photo frame" example script, then os.mount it.
Card contents can be SEEDED from the document: props.files is a JSON manifest of up to 16 {"name","ref"} entries — name is an 8.3 file name ([A-Z0-9_]{1,8} + optional .EXT), ref is a blob reference ("asset:/firmware/<file>" for bundled assets, "idb:<sha256>:<name>:<len>" for user uploads) — REFS ONLY, never inline bytes. The engine writes the files into the FAT16 image at boot. Image files use raw zero-decode formats the Inspector converts to on upload: .565 (u16 LE width + u16 LE height header, then RGB565 big-endian pixels — streams straight into a TFT RAMWR window) and .o64 (exactly 1024 bytes, SSD1306 page order). Video clips and animated GIFs convert the same way ("Add video…"): a .565 STREAM with an 8-byte header (u16 LE width, height, fps, frame count) followed by concatenated RGB565 frames, played paced by the "microSD photo frame" example script — the MCU never decodes video, exactly like real ST7735 video projects. See the "microSD photo frame" example.
gndvcccssckmosimiso
RFID reader (MFRC522)
rfid522

MFRC522 RFID reader on a 7-pin SPI breakout (gnd, vcc, rst, cs, sck, mosi, miso) with one virtual MIFARE Classic 1K tag. Present or remove the tag with the Inspector's "Hold tag to reader" toggle; its UID and block contents are editable there and persist with the project. HARDWARE SPI ONLY (same fixed pins as the microSD): on the ESP32 C6/C3/S2/S3 wire sck=g6, mosi=g7, miso=g2 and use MicroPython SPI(1) (the C6/C3 defaults; on S2/S3 pass sck=Pin(6), mosi=Pin(7), miso=Pin(2) explicitly); on the classic ESP32 wire sck=g18, mosi=g23, miso=g19 (SPI(2)); on the Uno wire sck=d13, mosi=d11, miso=d12; on the Pi Pico sck=GP18, mosi=GP19, miso=GP16. CS = any GPIO; RST can stay unwired (on-module pull-up). The register protocol is real (VersionReg 0x92, FIFO, CalcCRC coprocessor, Transceive/MFAuthent), so stock MFRC522 drivers run unmodified: REQA→ATQA 0x0004, anticollision→4-byte UID, SELECT→SAK 0x08, key auth (default FF FF FF FF FF FF), 16-byte block read/write, HALT. Auth is a plain key comparison (no Crypto1 cipher) and 7-byte-UID/NTAG variants are not modeled.

Arduino cloud compile provides MFRC522 1.4.12 (`#include <MFRC522.h>`). It uses the board’s fixed hardware-SPI pins and the modeled four-byte-UID MIFARE Classic 1K path.
Wiring off the hardware-SPI pins means the reader is never attached — VersionReg reads 0 and every driver init fails. Same fixed-pin contract as the microSD.
The tag answers only while "Hold tag to reader" is on — like a real card, it must stay in the field for the whole auth+read conversation.
No tag / wrong UID / wrong key surface as the TimerIRq timeout every driver maps to its own timeout status — that is the correct behaviour, not a bug.
MicroPython has NO frozen mfrc522 module: inline the ~60-line driver from the "RFID door lock" example script.
gndvccrstcssckmosimiso

Semis & ICs

Diode
diode

Silicon 1N4148, ~0.7 V drop. Pin a = anode, k = cathode; conducts a→k only.

ak
Vz
Zener
zener

props.breakdownVoltage (3.3/5.1/6.8/9.1/12). Wire CATHODE toward + for a shunt clamp at Vz.

ak
Schottky
schottky

Low-drop diode (~0.3 V). Pin a = anode, k = cathode.

ak
NPN
npn

2N2222-style BJT. Pin order on the board: e, b, c (left to right).

ebc
P
PNP
pnp

2N3906-style PNP BJT — the NPN's complement, β ≈ 200. Pin order on the board: e, b, c (left to right), same TO-92 order as the npn part. It conducts when the BASE is pulled BELOW the emitter by ~0.7 V, so the classic use is a HIGH-SIDE switch: emitter to +V, load from collector to ground, base to the driving pin through 1–10 kΩ. An MCU pin driven LOW turns it on, driven HIGH (or an emitter at 5 V with a 3.3 V pin) leaves it partly on — pull the base fully to the emitter rail to cut it off.

ebc
MOSFET
nmos

N-MOSFET. Pin order: g, d, s.

gds
741
Op-Amp
opamp

LM741 in a DIP-8 that must STRADDLE the channel: anchor on row e; the dy:-3 pins land on row f. Needs vcc and vee supplies.

nc1inninpveenc5outvccnc8
555
555 Timer
ne555

555 timer, DIP-8 straddling the channel (anchor row e). Classic astable: see the examples.

gndtrigoutresetctrlthresdischvcc
CAN
CAN transceiver
mcp2551

Microchip MCP2551 high-speed CAN transceiver, DIP-8 straddling the channel (anchor row e). Pins in package order: txd, vss, vdd, rxd, vref, canl, canh, rs. It is the PHYSICAL LAYER only — it turns one logic pin into the CANH/CANL differential pair and turns the pair back into one logic pin. Wire vdd to 5 V and vss to ground; tie rs to GND for high-speed mode (rs left unwired reads as standby and the drivers stay off). Put a 120 Ω resistor across canh/canl at EACH end of the bus. TXD low drives the pair dominant (canh ≈ 3.6 V, canl ≈ 1.4 V at 5 V into a 60 Ω terminated bus); TXD high leaves it recessive with both lines near 2.5 V. RXD is a comparator on the SOLVED differential voltage, low when the pair is dominant, so two nodes driving at once produce a real wired-AND: dominant always wins. An unpowered transceiver goes high-impedance and does not disturb the bus. Modeled from the MCP2551 datasheet: recessive and dominant levels, termination loading, receiver thresholds and hysteresis, power-on-reset levels, standby mode, the TXD permanent-dominant driver shutdown, and the 70/125 ns TXD-to-bus and 130/175 ns TXD-to-RXD propagation delays. NOT modeled: transmission-line reflections (so an unterminated bus still passes bits here, unlike a real one), RS slope-control slew shaping, thermal shutdown and CAN FD. IMPORTANT: this part does not give any board a CAN controller. No board on the bench can currently run a CAN peripheral, so use it by bit-banging txd and sampling rxd from ordinary GPIO pins. Do not tell users that CAN is supported on the UNO R4.

txdvssvddrxdvrefcanlcanhrs
NAND
NAND ×4
74hc00

Quad NAND, DIP-14 straddling the channel (anchor row e). Wire VCC and GND or outputs float.

1A1B1Y2A2B2YGND3Y3A3B4Y4A4BVCC
NOT
NOT ×6
74hc04

Hex inverter, DIP-14 straddling the channel.

1A1Y2A2Y3A3YGND4Y4A5Y5A6Y6AVCC
AND
AND ×4
74hc08

Quad AND, DIP-14 straddling the channel.

1A1B1Y2A2B2YGND3Y3A3B4Y4A4BVCC
OR
OR ×4
74hc32

Quad OR, DIP-14 straddling the channel.

1A1B1Y2A2B2YGND3Y3A3B4Y4A4BVCC
XOR
XOR ×4
74hc86

Quad XOR, DIP-14 straddling the channel.

1A1B1Y2A2B2YGND3Y3A3B4Y4A4BVCC
595
74HC595
74hc595

Serial-in/parallel-out shift register, DIP-16 straddling the channel. Tie mr HIGH and oe LOW. Clock data on shcp, latch to q0–q7 with stcp. q7s cascades.

q1q2q3q4q5q6q7gndq7smrshcpstcpoedsq0vcc
165
74HC165
74hc165

Parallel-in/serial-out shift register — the 595 run backwards: eight inputs become one wire into the MCU. DIP-16 straddling the channel (anchor row e, or the two rows share a strip). Wire vcc and gnd, tie ce LOW (clock enable), and read like a shiftIn: pulse pl LOW then HIGH to load d0–d7, then read q7 BEFORE each of eight rising cp edges — q7 gives d7 first, down to d0. q7b is the complement; ds takes the previous chip's q7 for a cascade. CE IS A SECOND CLOCK: the two inputs meet in an OR gate inside the chip, so a rising edge of (cp OR ce) shifts. Raising ce to "freeze" the register while cp is LOW therefore clocks it one extra time (the datasheet says to raise ce only while cp is HIGH), and driving ce with cp tied low clocks the part perfectly well. Simply tie ce to ground unless you mean it. Every d input is a real Schmitt input on the solved node (VIL 0.3·Vdd / VIH 0.7·Vdd), so a floating d pin reads low — use pull-ups or pull-downs on buttons. Timing: the read-back is sampled once per solver step, so hold every pl/cp level for at least ~10 µs. Measured on the emulated ESP32-C3 bit-banging it in MicroPython: 10 µs and above returned the wired byte every time, 6–8 µs was already unreliable, and 5 µs or less returned garbage. time.sleep_us(20) (or an Arduino shiftIn with delayMicroseconds spacers) is a safe pace; MHz-rate hardware SPI clocking of this part is NOT modeled.

plcpd4d5d6d7q7bgndq7dsd0d1d2d3cevcc

Instruments

Func Gen
funcgen

Signal source. props: waveform (sine|square|triangle|sawtooth), frequency Hz, amplitude V, offset V. Square 0–5 V = amplitude 2.5, offset 2.5.

siggnd
5.0V
Voltmeter
voltmeter

High-impedance meter between pos and neg; reading shows on the canvas.

posneg
14mA
Ammeter
ammeter

Near-zero-ohm shunt in series; reading shows on the canvas.

posneg