pimoroni-emu
Desktop emulator for Pimoroni devices. Run MicroPython and Raspberry Pi apps on your desktop with simulated displays, buttons, and touch input.
Note: This is an unofficial community project and is not affiliated with or endorsed by Pimoroni.
Screenshots
Badges & displays
| Tufty 2350 | Badger 2350 |
|---|---|
Badgeware (LED matrix)
| Blinky 2350 |
|---|
Inky
| Inky Frame 7.3" | Inky Impression 5.7" |
|---|---|
Presto
| Presto |
|---|
Install
pip install pimoroni-emulator
Or from source:
git clone --recurse-submodules https://github.com/iksaif/pimoroni-emu
cd pimoroni-emulator
pip install -e ".[dev]"
Usage
# Run an app on a specific device
pimoroni-emulator --device tufty apps/tufty/hello_badge.py
pimoroni-emulator --device presto apps/presto/touch_demo.py
pimoroni-emulator --device badger apps/badger/hello_badge.py
pimoroni-emulator --device inky_frame apps/inky_frame/hello_inky.py
pimoroni-emulator --device inky_impression apps/inky_impression/hello_impression.py
# Run Blinky apps (auto-detected from path)
pimoroni-emulator apps/blinky/snake.py
# Device is auto-detected from app path
pimoroni-emulator apps/tufty/hello_badge.py
# List all supported devices
pimoroni-emulator --list-devices
# Headless mode (for CI/testing)
pimoroni-emulator --device tufty --headless --max-frames 5 app.py
# Save frames to disk
pimoroni-emulator --device presto --autosave frames/ app.py
# Enable API call tracing
pimoroni-emulator --device tufty --trace app.py
# Scale display window
pimoroni-emulator --device tufty --scale 3 app.py
Keyboard controls
- Q / Escape - Quit
- A, S, D, F, G - Buttons A-E (device-dependent)
- Up / Down - UP/DOWN buttons (Tufty, Badger)
- Mouse click - Touch input (Presto)
QwSTPad gamepad (Presto, Blinky)
When an app creates a QwSTPad instance, a clickable gamepad widget appears below the display:
- Arrow keys - D-pad (U/D/L/R)
- Z / X / C / V - Face buttons (A/B/X/Y)
- = / - - Plus/Minus buttons
Running on a real Raspberry Pi with --hardware
For Inky HATs on a real Raspberry Pi, --hardware routes the emulator's
framebuffer to the physical panel via the upstream inky library:
pip install 'pimoroni-emulator[hardware]'
pimoroni-emulator --device inky_impression_73 --hardware --headless main.py
--headless is recommended (and auto-enabled when no display server is
available); add --trace to see every call to the real HAT (entry, args,
return value, elapsed time).
Bookworm: the SPI overlay
On Raspberry Pi OS Bookworm, the default device tree reserves the
SPI0 CE0/CE1 GPIOs as hardware chip-selects. On 7.3" Impression HATs
that GPIO is also the BUSY pin inky.show() polls — so show() blocks
forever (or returns silently with no flicker) until you free the pins.
Add dtoverlay=spi0-0cs to /boot/firmware/config.txt and reboot:
sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.bak
echo "dtoverlay=spi0-0cs" | sudo tee -a /boot/firmware/config.txt
sudo reboot
Symptom if missing: with --trace, you'll see [Hardware] -> show()
followed by no <- show line for minutes. The wiring on our side is
fine — userspace just can't read BUSY.
Compatibility matrix
Devices
| Family | Device | Display | Resolution | Library | Status |
|---|---|---|---|---|---|
| Tufty | Tufty 2350 | TFT IPS | 320x240 | PicoGraphics | Working |
| Blinky | Blinky 2350 | LED matrix | 39x26 | Badgeware | Working |
| Presto | Presto | TFT IPS touch | 480x480 | PicoGraphics | Working |
| Badger | Badger 2350 | E-ink mono | 296x128 | PicoGraphics | Working |
| Inky Frame | 7.3" | E-ink 6-color | 800x480 | PicoGraphics | Working |
| 5.8" | E-ink 7-color | 600x448 | PicoGraphics | Working | |
| 4.0" | E-ink 7-color | 640x400 | PicoGraphics | Working | |
| Inky Impression | 7.3" | E-ink 6-color | 800x480 | inky (RPi) | Working |
| 5.7" | E-ink 7-color | 600x448 | inky (RPi) | Working | |
| 4.0" | E-ink 7-color | 640x400 | inky (RPi) | Working | |
| 13.3" | E-ink 6-color | 1200x1600 | inky (RPi) | Working |
Mock modules
| Module | Coverage | Notes |
|---|---|---|
picographics |
Good | Drawing primitives, text, fonts, framebuffer |
pimoroni |
Good | Button class, RGBLED |
machine |
Partial | Pin, PWM, I2C, SPI stubs |
presto |
Good | Presto class, touch |
badger2040 |
Good | Badger2040 class |
badgeware |
Partial | Drawing API for Blinky |
inky |
Good | Inky, InkyImpression, auto-detect |
inky_frame |
Good | InkyFrame class |
network / socket |
Good | WiFi connect, sockets pass through to host |
jpegdec / pngdec |
Good | Decode via Pillow, render to framebuffer |
picovector |
Good | Vectors, polygons, .af fonts, SVG loading |
qwstpad |
Good | Gamepad input via keyboard/mouse, LED indicators |
| Sensors | Stubs | BME280, LTR559, LSM6DS3 |
Not yet working
Hard
- Memory constraints - Basic heap tracking exists (
--memory-tracking) viatracemallocwith CPython-to-MicroPython scaling, but it's approximate. True byte-accurate simulation would need a custom allocator. - I2C/SPI peripherals - Stubs return zeros. Full simulation would require modeling each breakout board's register map.
Testing
pytest tests/ -v
The test harness supports headless execution, screenshot capture, button simulation, and touch input:
from emulator.testing import DeviceTest
class TestMyApp(DeviceTest):
device = "tufty"
app = "apps/tufty/hello_badge.py"
def test_display(self):
self.run_frames(5)
self.screenshot("output.png")
def test_button(self):
self.click_button("A")
self.run_frames(3)
Architecture
emulator/
__main__.py # CLI entry point
main.py # App runner, event loop
devices/ # Device configs (resolution, buttons, features)
display/ # Renderers (TFT, LED matrix, e-ink)
hardware/ # Input simulation (buttons, touch, sensors)
mocks/ # MicroPython module replacements (~38 modules)
testing/ # Test harness and screenshot comparison
vendor/ # Upstream submodules (read-only reference)
apps/ # Demo applications
The emulator injects mock modules into sys.modules before running your app. Three mock profiles exist:
- PicoGraphics - For Tufty, Presto, Badger, Inky Frame
- Badgeware - For Blinky 2350
- inky - For Inky Impression (Raspberry Pi)
License
MIT. See LICENSE.
Vendor submodules under vendor/ are all MIT-licensed (Pimoroni Ltd).
Metadata
Release files for pimoroni-emulator 0.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pimoroni_emulator-0.5.1.tar.gz | 119.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pimoroni_emulator-0.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 279.0 kB
Release files / pimoroni_emulator-0.5.1.tar.gz
| Download URL | pimoroni_emulator-0.5.1.tar.gz |
|---|---|
| Size | 119.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
49e3aadabd6ec14e60549aae126bb80899478ce4f267bb03c4d7c3590f86bc69
|
|
BLAKE2b-256 checksum How to use checksums |
4b484087debaedb7f3128d1def2c12825c9ee1916a6a0d591b32ca0f5bcf2d8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency logRelease files / pimoroni_emulator-0.5.1-py3-none-any.whl
| Download URL | pimoroni_emulator-0.5.1-py3-none-any.whl |
|---|---|
| Size | 159.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8655697010423f7aff0e725915009505788108c5ed64fb64bad6ff0f4eb0f799
|
|
BLAKE2b-256 checksum How to use checksums |
1a4c95c92fdfddcbf6dd9b7b108cebdb1fd632c24bce5ac3b8461df0d9df5901
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency log