Display Hat Mini and Trixie - Struggling with Updating Python Script

I’m currently going through my Pi’s to update the older OS images to new ones. As part of that I have a Pi Zero with a Display Hat Mini that was running Buster Lite, and I’ve now updated it to Trixie Lite.

Unfortunately in doing so, the script which used to run fine on Buster is now having all sorts of issues on Trixie. From what I can see, a lot of the dependency packages (PIL and numpy at least) have updated, and now things are going bad on me and I’m in need of some help.

The current error that’s giving me grief is

  File "/home/darren/display/display.py", line 755, in <module>
    display_hat.display(img)
    ~~~~~~~~~~~~~~~~~~~^^^^^
TypeError: DisplayHATMini.display() takes 1 positional argument but 2 were given

as I can’t see how to work around it?

The relevant bits of the script are

WIDTH = DisplayHATMini.WIDTH
HEIGHT = DisplayHATMini.HEIGHT


def clear_display():
    global img, draw, disp
    img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
    draw = ImageDraw.Draw(img)
    return


display_hat = DisplayHATMini(buffer=None, backlight_pwm=True)
display_hat.on_button_pressed(button_callback)


while True:
    while DISPLAYSCREEN == "clock":
        clear_display()
        display_hat.set_backlight(True)
        x = datetime.datetime.now()
        today = datetime.date.today()
        date_string = today.strftime('%-d{suffix} %B')
        if (x.second / 2) == int(x.second / 2):
            draw_centred_text(img, x.strftime("%H:%M:%S"), 48, clockfont, 255, 255, 255)
        else:
            draw_centred_text(img, x.strftime("%H %M %S"), 48, clockfont, 255, 255, 255)
        draw_centred_text(img, x.strftime('%A'), 144, font28, 255, 255, 255)
        draw_centred_text(img, date_string.format(suffix=ordinal_suffix(today.day)), 192, font28, 255, 255, 255)
        draw_tags()
        display_hat.display(img)
        sleep(0.1)

draw_centred_text() and draw_tags() are defined elsewhere in the script and seem to be working (after some fixes), but the display line just before the sleep is giving the error above.

Can anyone share some guidance here, as I’m stuck :(

I assume it’s something around the definition in the clear_display() function, but what should the img set-up be?

This might help?
TypeError: ST7789.display() missing 1 required positional argument: ‘image’ - Support - Pimoroni Buccaneers

Posting the full file your uisng will also help.

I’ll post it tomorrow, as I’ll need to sanitise it a bit for some passwords etc.

Originally I did have both st7789 and display_hat in there, but that was the first thing that broke as I was getting errors that the GPIO was already in use.

Thanks for the help so far though, will get a script dump up when I can.

Mine uses st7789 because I was using this.

and this

Your code will use display_hat if your going by these examples.

I’ve put the python script on pastebin, with a few bits redacted (“removed” in the script).

It’s designed to interact with my MQTT broker and display data fed from that (and a few other places on my network).

Originally it was using both, but I’ve pulled out the disp = ST7789() bit as the two were now clashing (they worked together before under Bullseye and its older package versions).

Earlier today whilst looking for an ili9341 screen I came accross a display hat mini attached to a rpi Zero2 which I only vaguely remember what I was doing with it a couple of years ago. Apart from the main program I had been working on I saw it had a couple of noddy test progs so I thought I would install Trixie (64bit desktop) to see if it all still worked. Apart from an initial possible hiccup with VNC (I use it headless) that an update to trixie from the initial rpi load seem to have cured, when I ran the original test progs all seemed well. The installation was via the rpi imager and then I installed the displayhatmini in to a virtual env. I know this post does not address your issue but incase it helps I include one of my short test progs, that seems to work OK. I will look back tomorrow evening to see if you are still having issues and then look at your code snippet, but you probably would have solved the problem by then. So here is the test prog

from displayhatmini import DisplayHATMini as DHM
from PIL import Image, ImageDraw, ImageFont
import time
import sys

width = DHM.WIDTH
height = DHM.HEIGHT
print('(w) ',width,' x (h) ',height)

#img = Image.new('RGB', (disp.width, disp.height), color=(0,0,0))
#draw = ImageDraw.Draw(img)
buffer = Image.new("RGB", (width, height))
draw = ImageDraw.Draw(buffer)

dmini = DHM(buffer)
dmini.set_led(0.05, 0.05, 0.05)

all_white = (255,255,255)
all_red = (255,0,0)
all_green = (0,255,0)
all_blue = (0,0,255)
all_blank = (0,0,0)


def text(text, position, size, colour):
    #fnt = ImageFont.load_default()
    fnt = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", size)
    draw.text(position, text, font=fnt, fill=colour)
    dmini.display()

def rectangle(x,y,width,height,colour):
    draw.rectangle((x,y,width,height),colour)
    dmini.display()

def circle(x1,y1,x2,y2, outline_colour, fill_colour):
    draw.ellipse((x1,y1,x2,y2), outline=outline_colour, fill=fill_colour)
    dmini.display()

def slice(x1,y1,x2,y2,start_angle,end_angle,fill_colour,line_width):
    draw.pieslice((x1,y1,x2,y2),start_angle, end_angle, fill=fill_colour, width=line_width)
    dmini.display()

def blank():
    draw.rectangle((0,0,width,height),all_blank)
    dmini.display()


# draw a retangle that fills the whole screen with blue
rectangle(0,0,width,height,all_blue)

# draw some text onto the screen
toshow = "hello"
size = 30
text(toshow, (25, 50), size, all_white)

slice(100,160,160,200,10,180,all_white,1)


size = 20
while True:
    if dmini.read_button(dmini.BUTTON_X):
        print('button x pressed')
        blank()
        text('button x pressed', (0, 0), size, (255, 255, 255))
        time.sleep(0.1)
        dmini.set_led(0.05, 0.00, 0.00)
        rectangle(0,120,100,130,all_green)
        circle(100,160,160,220,all_green, all_blue)
        circle(200,160,260,220,all_red, all_green)
    if dmini.read_button(dmini.BUTTON_A):
        print('button A pressed')
        #blank()
        text('button A pressed', (0, 25), size, (255, 255, 255))
        time.sleep(0.1)
        dmini.set_led(0.00, 0.05, 0.00)
        rectangle(100,120,160,130,all_red)
        slice(100,160,160,220,90,220,all_red,5)
    if dmini.read_button(dmini.BUTTON_Y):
        print('button Y pressed')
        #blank()
        text('button Y pressed', (0, 50), size, (255, 255, 255))
        time.sleep(0.1)
        dmini.set_led(0.00, 0.0, 0.1)
        rectangle(0,120,160,130,all_green)
        slice(200,160,260,220,270,360,all_red,5)
        slice(200,160,260,220,0,70,all_red,5)
    if dmini.read_button(dmini.BUTTON_B):
        print('button B pressed')
        blank()
        time.sleep(0.1)
        dmini.set_led(0.00, 0.00, 0.00)
        sys.exit()

@DarrenHill
What error and what line number does it give when you run it now? Without the st7789 reference but with your redacted info in it. ;)

Technically, you could code it as st7789. That’s the driver chip it’s using. It just means adding in the extra config info, the spi pins etc. And only referencing st7789 in your code.
What caught me out is some examples used
disp = st7789.ST7789(
and some
display = ST7789(
and some
st7789 = st7789.ST7789(
My clip and past had two different references and thus errored out. The error message was not at all helpful in sorting it out though. Not for me with my basic Python skills.

Same as pasted in the first post - error on line 755.

File "/home/darren/display/display.py", line 755, in <module>
    display_hat.display(img)
    ~~~~~~~~~~~~~~~~~~~^^^^^
TypeError: DisplayHATMini.display() takes 1 positional argument but 2 were given

It looks like the displayhatmini package has ST7789 within it now, which is why I commented out the explicit package use of it (if both are currently used, there’s an error relating to something else already being in control of the GPIO pins - I forget the exact wording).

Essentially the script is currently in the same set-up as I posted to pastebin, obviously with the full non-redacted data in it. The ST7789 package is imported, but not currently used (notice that the disp = st7789.ST7789() bit is currently commented out).

I’m at the end of my own basic python skills, which is why I made this thread.

Worst case I can reflash the bullseye image I took before starting all this and reset everything back to working but obsolete. But I really want to move my Pi’s onto current versions of the OS.

Ok, just wanted to make sure we were on the same page / line. ;)
I’m just getting myself another cup of java, 6 AM here, and will have a look. :)
@DarrenHill
EDIT:
since you are using
from displayhatmini import DisplayHATMini, ST7789
I would change
display_hat = DisplayHATMini(buffer=None, backlight_pwm=True)
to
displayhatmini = DisplayHATMini(buffer=None, backlight_pwm=True)

And
display_hat.display(img)
to
displayhatmini.display(img)

I think I might also change
from displayhatmini import DisplayHATMini, ST7789
to
from displayhatmini import DisplayHATMini

Thanks. Unfortunately it gives the same error:

darren@DisplayPi:~/display $ python display.py
/home/darren/display/display.py:730: DeprecationWarning: Callback API version 1 is deprecated, update to latest version
  client = mqtt.Client()
Traceback (most recent call last):
  File "/home/darren/display/display.py", line 756, in <module>
    DisplayHATMini.display(img)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^
TypeError: DisplayHATMini.display() takes 1 positional argument but 2 were given

The depreciation warning I know how to fix and isn’t relevant here.

But I’m still stuck on the display one. Between this and the scroll hat mini (see my other thread), I’m starting to think updating was a bad idea!

Upgrading to trixie also caught me out.sudo pip install st7789 wouldn’t cut it anymore. I ended up doing the following

git clone https://github.com/pimoroni/st7789-python
cd st7789-python
./install.sh

Maybe @hel can help sort it out?

Just tried the install from this repackaged branch and Trixie and it seems to be working OK for me, though I had to pip uninstall rpi-gpio and pip install rpi-lgpio to make it work with Pi 5.

Our Display HAT Mini examples set up the PIL image/buffer at the beginning of the script and then draw into that, calling the display() function at the end without any parameters to update the screen.

Looks like you’re providing the update function in the DHM library with a PIL image as a parameter - I think that might be what’s causing your error here?

Thanks for that.

I already fell over and did the GPIO swap you mention (I’m on a Pi Zero W, for reference).

I think I already tried the display() without any parameter, but I’ll have a play again as I’ve tried a lot of stuff already and not sure if I tried that with the current set-up.

To be honest, I’m pondering either burning the whole thing down and rewriting it again from scratch, or just giving up and reflashing the Bullseye image where things worked (and before all this virtual environment monstrosity).

I too just had a quick look at the code as put on pastebin and cutting that code back to the essence of creating a DisplayHatMini instance I get the ‘TypeError: DisplayHATMini.display() takes 1 positional argument but 2 were given’ indicating that the method does not take any args except the auto provided self parameter.

I put my buster image back on my rpi Zero 2 and that also gave the same error with the example cut down code snippet, so whatever may have changed from the original working version of the program appears to be made some time back. I show the cut down snippet from the pastebin code that gives the error, and also another snippet of the way I created the DisplayHatMini instance way back on my Buster image that still works with Trixie.
Minimal snippet to show error:

mport sys
import datetime
import signal
import math

from signal import *
from time import sleep
from PIL import Image, ImageDraw, ImageFont
from displayhatmini import DisplayHATMini

WIDTH = DisplayHATMini.WIDTH
HEIGHT = DisplayHATMini.HEIGHT


clockfont = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 64)


DISPLAYSCREEN = "clock"
OLDSCREEN = ""
status = "stop"

display_hat = DisplayHATMini(buffer=None, backlight_pwm=True)


def clear_display():
    global img, draw, disp, WIDTH, HEIGHT
    img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
    draw = ImageDraw.Draw(img)
    return


while True:
    while DISPLAYSCREEN == "clock":
        clear_display()
        display_hat.set_backlight(True)
        display_hat.display(img)
        sleep(1)

and minimal example that works

mport sys
import datetime
import signal
import math

from signal import *
from time import sleep
from PIL import Image, ImageDraw, ImageFont
from displayhatmini import DisplayHATMini

WIDTH = DisplayHATMini.WIDTH
HEIGHT = DisplayHATMini.HEIGHT

clockfont = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 64)

GREEN = (0,200,0)
BLACK = (0,0,0)
buffer = Image.new('RGB', (WIDTH, HEIGHT))
draw = ImageDraw.Draw(buffer)
display_hat = DisplayHATMini(buffer)

def clear_screen():
    draw.rectangle((0,0,WIDTH,HEIGHT),BLACK)
    display_hat.display()

clear_screen()
draw.text((0,0),'hello', font=clockfont, fill=GREEN )
display_hat.display()

So no idea why your original example did once work, but perhaps the DisplayHatMini module changed in the past, but if so that change seems to have been some time back, at least compared to the version I had on my old SD card with its Buster image.

If I remove the img parameter (and change nothing else), it gives a different error but still fails:

Traceback (most recent call last):
  File "/home/darren/display/display.py", line 756, in <module>
    DisplayHATMini.display()
    ~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/local/lib/python3.13/dist-packages/displayhatmini/__init__.py", line 105, in display
    self.st7789.display(self.buffer)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/st7789/__init__.py", line 364, in display
    pixelbytes = self.image_to_data(image, self._rotation)
  File "/usr/local/lib/python3.13/dist-packages/st7789/__init__.py", line 372, in image_to_data
    image = numpy.array(image.convert("RGB"))
                        ^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'convert'

So it looks like the st7789 in DisplayHATMini wants something passed to it?

Anyway I’m going to take an image of what we have at the moment (broken as it is), then reimage the bullseye to sanity check that the code does work there and then stop and think how to handle this (probably a rewrite from scratch using the pong.py and the various scripts in this thread as a template).

@SirFico has all the relevant lines in his code: you first create an empty “image”-buffer, then pass it to the DisplayHatMini-object you create, and later you display it.

OK back on this now, after having confirmed that the original script does indeed run fine under Bullseye and that era packages.

Anyway started to rebuild using the pong.py example (and @SirFico code above).

It’s no longer crashing, however it’s not displaying anything as I think my code was using ST7789 type commands or something. Using draw.text seems clear enough, but will need to rewrite the script to do so rather than the current method (and will need to rework the centred text function).

Anyway progress is being made, slowly but surely!

On a similar note, I ended up going back to Bullseye on my Grow Hat Mini setups. It was the only way to get the installer to run without errors. Just a FYI post.

I’m close now - it’s up and running but unfortunately the display is flashing for the clock display as I have to clear it each time around otherwise the seconds (and then minutes) overwrite one another and tend towards h8:88:88 or something similar.

It’s close, but not there yet…

Edited to add - got it - don’t clear the display, just draw the black background as part of the clock update, then it works as required!

I think there’s a couple of more tweaks to make, but this one’s done…

2 Likes