# Inky: driving Pimoroni e-paper displays from a Raspberry Pi

> Inky is a MIT licensed Python library that turns a Raspberry Pi into a driver for Pimoroni e-paper displays, covering the pHAT, the wHAT and the Inky Impression colour range. It suits makers building low frequency dashboards, name badges or timetable screens, and it is the wrong tool for anything that needs a fast refresh, since e-paper cannot do that.

**pimoroni/inky** — Combined library for V2/V3 Inky pHAT and Inky wHAT.

- Repository: https://github.com/pimoroni/inky
- Website: https://shop.pimoroni.com/?q=inky
- Stars: 862 · Forks: 163
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/pimoroni-inky

## E-paper panels that hold an image until you change it

The displays Inky drives are the kind of screen that does not need refreshing sixty times a second. The Inky pHAT is a 250x122 pixel panel offered in red, black and white, yellow, black and white, or black and white, and the README positions it for name tags and very low frequency information such as a daily calendar or a weather overview. The Inky wHAT is 400x300 pixels in the same colour options, with enough resolution for detailed to-do lists, multi day forecasts and bus timetables. The Inky Impression line goes further, from a 4.0 inch panel up to 13.3 inches, aimed at colour graphics and denser data.

The audience is a maker with a spare Raspberry Pi and a project that only needs to change a few times a day. That framing is the whole appeal and also the whole limit. E-paper holds its image without power, which is why these projects work on a Pi with no display output. The same physics means a refresh takes seconds and shows ghosting from the previous frame, so a display that updates continuously is the wrong target for this hardware.

Pimoroni writes the library and sells the panels, which is why the driver stays in step with the boards rather than depending on a third party reverse engineering effort.

## EEPROM auto detection removes the board guesswork

The cleanest entry point is two lines. Inky can identify your board from information stored in its EEPROM and configure itself accordingly, and the README calls this the easiest way to work with recent Inky displays.

```python
from inky.auto import auto
display = auto()
```

Once the object exists, the panel geometry and palette can be read back from it, which is useful when a script has to size a drawing to the screen rather than assume a resolution:

```python
display.colour
display.resolution
```

This is the mechanism that keeps the library simple for newcomers. Without it, the same code would need editing for every panel, and the fact that it works at all depends on the board carrying an EEPROM. Older Inky displays do not have one, and for those the class has to be chosen by hand.

## Older boards without an EEPROM need InkyPHAT or InkyWHAT by hand

The manual path is a two step decision: pick the class, then pick a colour. The README instructs you to load the pHAT module from the Inky library, then instantiate it with one of the colours 'red', 'yellow' or 'black'.

```python
from inky import InkyPHAT

display = InkyPHAT('red')
```

The wHAT follows the same pattern with its own class.

```python
from inky import InkyWHAT

display = InkyWHAT('red')
```

Note what the manual path costs you. With auto() you can query display.colour and display.resolution and let the library work out the geometry. With a manual class you state the colour, and the class name carries the resolution. That is a small difference, but it is the difference between code that survives being moved to a different panel and code that does not, so treat the manual path as a fallback for hardware that predates the EEPROM rather than as an equivalent.

## Three calls do the work: set_image, set_border, show

Once a display object exists, the API surface is small. The README says there are only three methods you need to be concerned with, and that narrowness is a feature for a library that talks to a slow panel.

The first sets the content. You can hand it a PIL image, a numpy array or a list, and it lands in the internal buffer. The image dimensions should match the panel you are using.

```python
display.set_image(image)
```

The second sets the frame colour, which is what gives the pHAT and wHAT their distinctive look.

```python
display.set_border(colour)
```

The value should be one of inky.RED, inky.YELLOW, inky.WHITE or inky.BLACK, and which of those are available depends on the panel type. The third call pushes everything to the panel.

```python
display.show()
```

The ordering matters. set_image and set_border only fill internal state, and show is the point where the e-paper actually changes. That separation lets you compose an image and pick a border without paying the refresh cost for a frame you never wanted to display.

## The full install puts everything in a pimoroni virtual environment

The recommended path is an installation script. The README describes it as creating an easy installation script that installs all pre-requisites, and the sequence is clone, enter the directory, run the script.

```bash
git clone https://github.com/pimoroni/inky
cd inky
./install.sh
```

The important detail comes next: libraries are installed in the pimoroni virtual environment, and you need to activate it to run the examples.

```bash
source ~/.virtualenvs/pimoroni/bin/activate
```

That activation step is the single most common source of confusion, and the troubleshooting section names the symptom directly. A ModuleNotFoundError: No module named 'inky' message, on the assumption that install.sh has already run, means the virtual environment is not active.

A second variant exists for anyone who wants the newest code or intends to contribute. Passing the unstable flag installs the development version from the clone rather than the released library.

```bash
git clone https://github.com/pimoroni/inky
cd inky
./install.sh --unstable
```

## A PyPI install leaves I2C and SPI switches for you

There is a third route for people who want the stable library from PyPi and prefer to configure the system themselves. The README sets out the three commands, starting with a virtual environment created with system site packages.

```bash
python3 -m venv --system-site-packages $HOME/.virtualenvs/pimoroni
source ~/.virtualenvs/pimoroni/bin/activate
pip install inky
```

The catch is stated plainly: this path makes no configuration changes, so you may also need to enable the interfaces the hardware uses.

```bash
sudo raspi-config nonint do_i2c 0
sudo raspi-config nonint do_spi 0
```

Either command can be replaced by running raspi-config or the graphical Raspberry Pi Configuration UI and enabling the interfaces there. For a first install on a clean image, the script route is less work precisely because it takes care of this, but for a Pi whose configuration you already manage yourself, the manual path avoids the script rewriting things.

The repository also ships an uninstall.sh, and the Makefile exposes make install and make uninstall targets that call those two scripts, so removal is not a manual hunt through site-packages.

## SPI chip select claims the pins and needs a dtoverlay line

One failure mode deserves its own attention, because the error message does not name the fix. On a Pi where SPI chip select is enabled, the library reports that some pins are in use, and the message names chip select on line 8, GPIO8, currently claimed by spi0 CS0. The fix is to disable that chip select, which the README describes as adding a dtoverlay entry to the firmware configuration.

```
dtoverlay=spi0-0cs
```

The line goes into /boot/firmware/config.txt. The reason it is needed is worth understanding: the Raspberry Pi reserves a small number of GPIO lines for the SPI chip select function, and on newer boards those lines overlap with the ones the display hardware uses. Disabling the chip select frees them.

A second dependency failure has a different cause. A ModuleNotFoundError for font_hanken_grotesk means the example dependencies are missing rather than the library, and the repository points at requirements-examples.txt for the list. The install script handles this for you; a bare pip install inky does not, so examples can fail on a font package while the library itself imports cleanly.

## The migration note tells you where the drawing code went

If you are moving from the old inkyphat library, the README is unusually direct about what changed. Many of the drawing and image manipulation functions were removed from Inky, because those functions were always supplied by PIL in the first place. The recommended approach is to build and prepare the image with PIL and hand the finished result to Inky through set_image.

That is a sensible boundary. The library handles the panel protocol, the palette and the refresh, while the imaging toolkit stays where it belongs. The README suggests the PIL ImageDraw module for text, lines and shapes, and links to the Pillow ImageDraw documentation.

The repository layout backs this up. The examples directory separates the phat and what variants and includes a name-badge.py, a logo.py and a clean.py, plus a 7color and spectra6 folder for the colour Inky Impression panels. There is also an identify.py, which fits neatly with the auto() path described earlier.

One inconsistency is worth flagging for anyone pinning versions. The README says the library requires Python 3.7 or later, while pyproject.toml declares requires-python as 3.9 or later. The package metadata is the authoritative constraint for a pip install, and the classifiers list Python 3.9 through 3.13.

## Conclusion

Inky is a sensible choice for anyone building a slow changing screen on a Pi, such as a name badge, a daily schedule or a multi day forecast, and the auto() path removes the only configuration step that used to require knowing your board revision. It is a poor fit for anything that needs animation, live video or a sub second refresh, because that limit comes from the e-paper hardware rather than the library. Before writing your own script, check that your display exposes an EEPROM, because auto detection depends on it and older boards without one must be instantiated by hand as InkyPHAT or InkyWHAT, and confirm that SPI chip select is disabled with dtoverlay=spi0-0cs in /boot/firmware/config.txt before you blame the library for a blank panel.

## FAQ

### How do I install Inky on a Raspberry Pi?

The recommended path is the installation script: clone the repository, enter the inky directory and run ./install.sh. Libraries are installed in the pimoroni virtual environment, which you activate with source ~/.virtualenvs/pimoroni/bin/activate before running examples.

### How do I set an image on an Inky display?

Use display.set_image(image) with a PIL image, numpy array or list whose dimensions match the panel, then call display.show(). The border is set separately with display.set_border(colour) using inky.RED, inky.YELLOW, inky.WHITE or inky.BLACK.

### What do I do if I get ModuleNotFoundError: No module named 'inky'?

Assuming install.sh has already run, the README says to check that your virtual environment is active, which for the installer created environment means sourcing ~/.virtualenvs/pimoroni/bin/activate.

### How do I fix the chip select pin error on Inky?

The README says to add dtoverlay=spi0-0cs to /boot/firmware/config.txt, which disables the SPI chip select that currently claims the GPIO8 line.

### Does Inky work with older displays that have no EEPROM?

You instantiate the board class yourself instead of using auto(), for example InkyPHAT('red') or InkyWHAT('red'). The auto() path relies on the EEPROM to identify the board.

## Sources

- [License: MIT](https://github.com/pimoroni/inky/blob/main/LICENSE)
- [pimoroni/inky on GitHub](https://github.com/pimoroni/inky)
- [Project website](https://shop.pimoroni.com/?q=inky)
- [README](https://github.com/pimoroni/inky/blob/main/README.md)
- [Releases](https://github.com/pimoroni/inky/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pimoroni-inky
