OLED (128x128, Breakout > SPI Python Luma Install issue

1.12" Mono OLED (128x128, white/black) Breakout

Raspberry Pi 400 running the latest Pi OS, fully updated.
Starting on the shop page and following the get up and running instructions got me this.

udo pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled

kyrie@pi400:~ $ sudo pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled
[sudo] password for kyrie: 
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.
    
    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.
    
    For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
kyrie@pi400:~ $ 

So I back tracked and clicked the link to
Luma Python Library
The on to the install instructions.
install instructions
And finally to the software install instructions.
software install instructions

Which led me down this rabbit hole?

python3 -m venv ~/luma-env
~/luma-env/bin/python -m pip install --upgrade luma.oled

kyrie@pi400:~ $ ~/luma-env/bin/python -m pip install --upgrade luma.oled
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting luma.oled
  Downloading https://www.piwheels.org/simple/luma-oled/luma_oled-3.15.0-py3-none-any.whl.metadata (27 kB)
Collecting luma.core>=2.4.1 (from luma.oled)
  Downloading https://www.piwheels.org/simple/luma-core/luma_core-2.5.3-py3-none-any.whl.metadata (30 kB)
Collecting pillow>=9.2.0 (from luma.core>=2.4.1->luma.oled)
  Downloading pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (9.1 kB)
Collecting smbus2 (from luma.core>=2.4.1->luma.oled)
  Downloading https://www.piwheels.org/simple/smbus2/smbus2-0.6.1-py2.py3-none-any.whl.metadata (7.1 kB)
Collecting cbor2 (from luma.core>=2.4.1->luma.oled)
  Downloading cbor2-6.1.3-cp313-cp313-manylinux_2_28_aarch64.whl.metadata (5.5 kB)
Downloading https://www.piwheels.org/simple/luma-oled/luma_oled-3.15.0-py3-none-any.whl (33 kB)
Downloading https://www.piwheels.org/simple/luma-core/luma_core-2.5.3-py3-none-any.whl (72 kB)
Downloading pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (6.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.3/6.3 MB 1.2 MB/s eta 0:00:00
Downloading cbor2-6.1.3-cp313-cp313-manylinux_2_28_aarch64.whl (457 kB)
Downloading https://www.piwheels.org/simple/smbus2/smbus2-0.6.1-py2.py3-none-any.whl (11 kB)
Installing collected packages: smbus2, pillow, cbor2, luma.core, luma.oled
Successfully installed cbor2-6.1.3 luma.core-2.5.3 luma.oled-3.15.0 pillow-12.3.0 smbus2-0.6.1
kyrie@pi400:~ $ 

kyrie@pi400:~ $ sudo apt-get update
Hit:1 http://deb.debian.org/debian trixie InRelease
Hit:2 http://deb.debian.org/debian trixie-updates InRelease
Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
Hit:4 http://archive.raspberrypi.com/debian trixie InRelease    
Reading package lists... Done    

kyrie@pi400:~ $ sudo apt-get install python3 python3-pip python3-pil libjpeg-dev zlib1g-dev libfreetype6-dev liblcms2-dev libopenjp2-7 libtiff5 -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'libfreetype-dev' instead of 'libfreetype6-dev'
E: Unable to locate package libtiff5

kyrie@pi400:~ $ sudo apt-get install python3-imaging
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package python3-imaging is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  python3-pil:armhf python3-pil

E: Package 'python3-imaging' has no installation candidate

kyrie@pi400:~ $ sudo apt-get install python3-pil
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3-pil is already the newest version (11.1.0-5+deb13u4).
python3-pil set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

kyrie@pi400:~ $ sudo usermod -a -G spi,gpio,i2c kyrie
kyrie@pi400:~ $ 

kyrie@pi400:~ $ sudo pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.
    
    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.
    
    For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
kyrie@pi400:~ $ 

I think, somewhere in there, I was supposed to activate the virtual environment?
But where and when? Maybe I missed it but, why was that not mentioned?
If thats not it what am I doing wrong?

You either have to update the venv (which basically changes your PATH-variables), or start the python-interpreter directly from the venv. You did the latter:

~/luma-env/bin/python -m pip install --upgrade luma.oled

This is kind of a on-the-fly venv: it is only active during the execution of the python program. In your case the python program is running the pip-module which in turn is exactly the same that the pip command does.

So everything is fine at this stage. Now that you installed the software within your venv, you should indeed activate it before you start testing:

source ~/luma-env/bin/activate

This saves you from always giving the complete path to the python interpreter, python3 is enough after that (as I said above, the venv changes your PATH, i.e. how programs are found, so python3 is actually searched in ~/luma-env/bin first).

I’m just trying to follow the instructions as they are detailed. Like the average joe would. ;)

kyrie@pi400:~ $ source ~/luma-env/bin/activate
(luma-env) kyrie@pi400:~ $ sudo pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled
[sudo] password for kyrie: 
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.
    
    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.
    
    For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
(luma-env) kyrie@pi400:~ $ python3 -m venv ~/luma-env
(luma-env) kyrie@pi400:~ $ source ~/luma-env/bin/activate
(luma-env) kyrie@pi400:~ $ sudo pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.
    
    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.
    
    For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
(luma-env) kyrie@pi400:~ $ 

Remove the sudo. Running as root installs into the global python environment, not in the venv you just created for your kyrie user.

Will do. =) I’ll give it another go latter on tonight.

kyrie@pi400:~ $ python3 -m venv ~/luma-env
kyrie@pi400:~ $ source ~/luma-env/bin/activate
(luma-env) kyrie@pi400:~ $ pip3 install git+git://github.com/rm-hull/luma.oled.git#egg=luma.oled
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting luma.oled
  Cloning git://github.com/rm-hull/luma.oled.git to /tmp/pip-install-ox_coxj9/luma-oled_67c15d67da834732b2b2b3a8d9ec400c
  Running command git clone --filter=blob:none --quiet git://github.com/rm-hull/luma.oled.git /tmp/pip-install-ox_coxj9/luma-oled_67c15d67da834732b2b2b3a8d9ec400c
  fatal: unable to connect to github.com:
  github.com[0: 140.82.114.4]: errno=Connection timed out

  error: subprocess-exited-with-error
  
  × git clone --filter=blob:none --quiet git://github.com/rm-hull/luma.oled.git /tmp/pip-install-ox_coxj9/luma-oled_67c15d67da834732b2b2b3a8d9ec400c did not run successfully.
  │ exit code: 128
  ╰─> See above for output.
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error

× git clone --filter=blob:none --quiet git://github.com/rm-hull/luma.oled.git /tmp/pip-install-ox_coxj9/luma-oled_67c15d67da834732b2b2b3a8d9ec400c did not run successfully.
│ exit code: 128
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.
(luma-env) kyrie@pi400:~ $ 

Just about ready to give up on this. The instructions / documentation isn’t what it should be.

Yes, these instructions are just wrong. Replace this with

pip3 install git+https://github.com/rm-hull/luma.oled.git#egg=luma.oled

Using git://... instead of https://... only works if you use your own repositories on git and enabled ssh for accessing them. https-access is anonymous and should work.

OK, I’ll try that. I’ve swapped my original SD Card back in with my clean stock install. But I haven’t nuked the other SD card with the Luma stuff on it just yet. It would be nice to know if the OLED Breakout works.

It’s just getting ridiculous now, instruction wise, as in the lack of.

kyrie@pi400:~ $ python3 -m venv ~/luma-env
kyrie@pi400:~ $ source ~/luma-env/bin/activate
(luma-env) kyrie@pi400:~ $ pip3 install git+https://github.com/rm-hull/luma.oled.git#egg=luma.oled
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting luma.oled
  Cloning https://github.com/rm-hull/luma.oled.git to /tmp/pip-install-iniseh9h/luma-oled_bbcc196144f54bca9283f2a9641667b2
  Running command git clone --filter=blob:none --quiet https://github.com/rm-hull/luma.oled.git /tmp/pip-install-iniseh9h/luma-oled_bbcc196144f54bca9283f2a9641667b2
  Resolved https://github.com/rm-hull/luma.oled.git to commit 4f73ee3a5d5f95144af84ab51e7e07190ae42915
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: luma.core>=2.4.1 in ./luma-env/lib/python3.13/site-packages (from luma.oled) (2.5.3)
Requirement already satisfied: pillow>=9.2.0 in ./luma-env/lib/python3.13/site-packages (from luma.core>=2.4.1->luma.oled) (12.3.0)
Requirement already satisfied: smbus2 in ./luma-env/lib/python3.13/site-packages (from luma.core>=2.4.1->luma.oled) (0.6.1)
Requirement already satisfied: cbor2 in ./luma-env/lib/python3.13/site-packages (from luma.core>=2.4.1->luma.oled) (6.1.3)
(luma-env) kyrie@pi400:~ $ sudo git clone https://github.com/rm-hull/luma.examples
[sudo] password for kyrie: 
Cloning into 'luma.examples'...
remote: Enumerating objects: 1124, done.
remote: Counting objects: 100% (378/378), done.
remote: Compressing objects: 100% (100/100), done.
remote: Total 1124 (delta 317), reused 278 (delta 276), pack-reused 746 (from 1)
Receiving objects: 100% (1124/1124), 5.61 MiB | 1.52 MiB/s, done.
Resolving deltas: 100% (728/728), done.
(luma-env) kyrie@pi400:~ $ python3 bounce.py --display sh1106 --height 128 --rotate 2 --interface spi --gpio-data-command 9
python3: can't open file '/home/kyrie/bounce.py': [Errno 2] No such file or directory
(luma-env) kyrie@pi400:~ $ cd examples
bash: cd: examples: No such file or directory
(luma-env) kyrie@pi400:~ $ dir
Desktop  Documents  Downloads  luma-env  luma.examples	Music  Pictures  Public  Templates  Videos
(luma-env) kyrie@pi400:~ $ cd luma.examples
(luma-env) kyrie@pi400:~/luma.examples $ python3 bounce.py --display sh1106 --height 128 --rotate 2 --interface spi --gpio-data-command 9
python3: can't open file '/home/kyrie/luma.examples/bounce.py': [Errno 2] No such file or directory
(luma-env) kyrie@pi400:~/luma.examples $ dir
conf  CONTRIBUTING.rst	examples  LICENSE.rst  Pipfile	Pipfile.lock  pyproject.toml  pytest.ini  README.rst  setup.cfg  setup.py  tests  tox.ini
(luma-env) kyrie@pi400:~/luma.examples $ cd examples
(luma-env) kyrie@pi400:~/luma.examples/examples $ python3 bounce.py --display sh1106 --height 128 --rotate 2 --interface spi --gpio-data-command 9
^[Traceback (most recent call last):
  File "/home/kyrie/luma.examples/examples/bounce.py", line 80, in <module>
    device = get_device()
  File "/home/kyrie/luma.examples/examples/demo_opts.py", line 59, in get_device
    device = cmdline.create_device(args)
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/cmdline.py", line 240, in create_device
    device = Device(serial_interface=interface(), **params)
                                     ~~~~~~~~~^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/cmdline.py", line 150, in spi
    return spi(port=self.opts.spi_port,
               device=self.opts.spi_device,
    ...<6 lines>...
               gpio_RST=self.opts.gpio_reset,
               gpio=self.gpio or GPIO)
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/interface/serial.py", line 302, in __init__
    bitbang.__init__(self, gpio, transfer_size, reset_hold_time, reset_release_time, DC=gpio_DC, RST=gpio_RST)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/interface/serial.py", line 185, in __init__
    self._gpio = gpio or self.__rpi_gpio__()
                         ~~~~~~~~~~~~~~~~~^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/lib.py", line 23, in __rpi_gpio__
    import RPi.GPIO as GPIO
ModuleNotFoundError: No module named 'RPi'
(luma-env) kyrie@pi400:~/luma.examples/examples $ python3 bounce.py --display sh1106 --height 128 --rotate 2 --interface spi --gpio-data-command 9 --spi-device 0
Traceback (most recent call last):
  File "/home/kyrie/luma.examples/examples/bounce.py", line 80, in <module>
    device = get_device()
  File "/home/kyrie/luma.examples/examples/demo_opts.py", line 59, in get_device
    device = cmdline.create_device(args)
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/cmdline.py", line 240, in create_device
    device = Device(serial_interface=interface(), **params)
                                     ~~~~~~~~~^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/cmdline.py", line 150, in spi
    return spi(port=self.opts.spi_port,
               device=self.opts.spi_device,
    ...<6 lines>...
               gpio_RST=self.opts.gpio_reset,
               gpio=self.gpio or GPIO)
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/interface/serial.py", line 302, in __init__
    bitbang.__init__(self, gpio, transfer_size, reset_hold_time, reset_release_time, DC=gpio_DC, RST=gpio_RST)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/interface/serial.py", line 185, in __init__
    self._gpio = gpio or self.__rpi_gpio__()
                         ~~~~~~~~~~~~~~~~~^^
  File "/home/kyrie/luma-env/lib/python3.13/site-packages/luma/core/lib.py", line 23, in __rpi_gpio__
    import RPi.GPIO as GPIO
ModuleNotFoundError: No module named 'RPi'
(luma-env) kyrie@pi400:~/luma.examples/examples $ python3 bounce.py --display sh1106 --height 128 --rotate 2 --interface spi --gpio-data-command 9 --spi-device 0


@hel

Yep, two errors: you cloned the examples repo with sudo. This is not necessary, but should hopefully do no harm.

Second problem: this is old code, that still uses the RPi.GPIO module which is no longer available on modern systems. There is a compatibility shim though. I did not test it:

sudo apt-get update    
sudo apt-get -y install python-rpi.lgpio

Note the comment here: “This is specifically handy for running older code. You will need to remove the original rpi-gpio library so that they don’t clash.”

Sigh, at this point all I want to do is prove it actually works as advertised.
Nothing in the Learn section OLED related, and the product page instructions are outdated. It would be nice if somebody from Pimoroni would chime in?

If you just want to test the screen works and have a handy micropython board you might like to have a go with this driver and demo code. GitHub - peter-l5/SH1107: MicroPython driver for SH1107 OLED displays (128x128 and 128x64 pixels) · GitHub

@SirFico
Been there done that.

Ah, so you did😀. Maybe your screen is duff as I’m surprised the demo spi program, as simply amended for the breakout garden pins, did not work. The author specifically indicated it was tested on the pimoroni screen. Did you actually try to run the demo program ( pins amended ) or just a homebrew. If so it may be worthwhile to raise an issue in the authors GitHub. I see that one of the top MicroPython bods added some stuff to make this module mip installable, so it seems to be approved code.

Yesterday I soldered on a male header so I could use a solder less breadboard. And then tried to use the Pins he used. But I find his code confusing pin us wise, IE what pins is he actually using. Namely the second line below.

spi1 = SPI(1, baudrate=1_000_000, sck=Pin(14), mosi=Pin(15), miso=Pin(12))
display = sh1107.SH1107_SPI(64, 128, spi1, Pin(21), Pin(20), Pin(13))

Managed to track down a SPI OLED and gave it a try - this is what worked for me on a Pi 5 with Trixie:

I think using --system-site-packages flag when setting up the venv was the crucial step missing from the luma instructions. This is needed so that the venv can see the apt version of rpi-lgpio (which was already installed).

I see this pesky screen is being tackled from all directions, I expect the screen may surrender soon. But a comment on the micropython lib and demo code with the confusing pin parameters, I see that the example code line:

display = sh1107.SH1107_SPI(64, 128, spi1, Pin(21), Pin(20), Pin(13))

has extra Pins defined in addition to the spi1 pins which relate to the SH1107_SPI class __init__ referring to pins for dc, res=None, cs=None parameters. Presumably, as res and cs are defaulted to None you could just define a dc pin. But if you go with the pins as defined in the demo on your breadboard setup, what results do you get when you run the sh1107 demo v319 spi 128x128.py file.

@hel Thank you, for taking the time to look at this. When I get some time I’ll give that a go. Right now I’m making some success with getting it to work on a Pico.

@SirFico I have it working now on a Pico.

The instructions on the shop page should hopefully be a bit more helpful now :)

A big thank you for that. I hope to give it a go over the weekend.