Need help with some Unicorn HD code, display color issue

I’m running the code posted below on a Unicorn HD. It displays the Day, Date and Time in a repeating scrolling message. The only issue I have is with setting the text color.
Something in the code is overriding my r, g, b = statement at the top of the file. The code is modified code taken from the text.py example. The code that needs to changed is i believe the following, I just have no idea what to change?

  for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

The full file is as follows.

#!/usr/bin/env python

import time
from sys import exit

from PIL import Image, ImageDraw, ImageFont

import unicornhathd

unicornhathd.rotation(90)
unicornhathd.brightness(0.6)

FONT = ('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12)

r, g, b = (0, 255, 255)

while True:

    text = time.strftime("It's %A %B %-d %-I:%M:%p")
    
    width, height = unicornhathd.get_shape()

    text_x = width
    text_y = 2


    font_file, font_size = FONT

    font = ImageFont.truetype(font_file, font_size)

    text_width, text_height = width, 0

    text = time.strftime("It's %A %B %-d %-I:%M:%p")
    
    w, h = font.getsize(text)
    text_width += w + width
    text_height = max(text_height, h)

    
    image = Image.new('RGB', (text_width, max(16, text_height)), (0, 0, 0))
    draw = ImageDraw.Draw(image)

    offset_left = 0

    draw.text((text_x + offset_left, text_y), text, font=font)

    offset_left += font.getsize(text)[0] + width

    for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

        unicornhathd.show()
        time.sleep(0.01)

So you set the colour here:

r, g, b = (0, 255, 255)

But when you actually set the pixels on the HAT the code is using whatever colour the pixel is in the image:

                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

There are probably two ways to do this you could remove the r, g, b = [int(n) for n in pixel] line so that the line saying unicornhathd.set_pixel(width - 1 - x, y, r, g, b) uses the r, g and b values you’ve defined, or if you check the Pillow documentation for Draw.text it has an argument for colour:

ImageDraw.text(xy, text, fill=None

fill – Color to use for the text.

So you’d modify your line to read

draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))

If the draw.text function has an argument for adding colour I think it would be better to do it there. At a glance I think that’s the issue.

1 Like

Thanks for the reply, I already tried remarking out the r, g, b = [int(n) for n in pixel] line and that just got me all the pixels lit up in a solid color.
I’ll have a look at the other option and let you how it works out.

Ah yes, sorry, that will set ALL pixels to r, g, b rather than just the text. The function method is the one you want then.

I changed that one line to
draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))
It sort of worked? I get the correct color for one show of the message but then nothing, just a blank screen. No error and I know my code is still running.
I have a print statement right after the
text = time.strftime("It's %A %B %-d %-I:%M:%p")
that says time updated each time that line is run.
I’m getting
time updated
time updated
etc.

EDIT: I found a fix, not sure if its the proper way to do it but it works.
I just put a r, g, b =(0, 0, 255) in the while True loop just before the draw.text line.

So that probably happens because r, g and b are getting defined twice: once at the top of the script and then every time it goes through the while true loop. The first time the loop runs it uses the colours you define at the top of the script to draw the text, but by the end of the loop r, g and b are set to whatever colour the last pixel was and that gets used the next time the text is drawn. You could also fix this by renaming the text colours to something like text_r, text_g, text_b.

Actually its not a big deal as I am going to want to add more messages. Each one showing in order one after the other, and I am going to want to change my text color on the fly. I’ll be setting it in the while true section anyway.
I have working code for the Unicorn Mini just trying to switch to a Unicorn HD.

I have to thank you again @Shoe for helping me sort this out. I would have never figured out that simple fix.

Here is the my full code that shows the Day, Date, Time, Temperature, Humidity and Barometric Pressure, an endlessly repeating message. The color of each message changes based on conditions. The temperature text turns Orange at 25c then red at 30c for example. I just figured you’d like to see the end result. There likely is some stuff that could go above the while True to clean it up but it works, so I’ll play with that another day.

#!/usr/bin/env python

import time
from sys import exit

from PIL import Image, ImageDraw, ImageFont

import unicornhathd

try:
    from smbus2 import SMBus
except ImportError:
    from smbus import SMBus
from bme280 import BME280

bus = SMBus(1)
bme280 = BME280(i2c_dev=bus)

unicornhathd.rotation(90)
unicornhathd.brightness(0.6)

FONT = ('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12)

while True:

    text = time.strftime("It's %A %B %-d %-I:%M:%p")

    #print("time updated")

    width, height = unicornhathd.get_shape()

    text_x = width
    text_y = 2


    font_file, font_size = FONT

    font = ImageFont.truetype(font_file, font_size)

    text_width, text_height = width, 0

    text = time.strftime("It's %A %B %-d %-I:%M:%p")
    
    w, h = font.getsize(text)
    text_width += w + width
    text_height = max(text_height, h)

    
    image = Image.new('RGB', (text_width, max(16, text_height)), (0, 0, 0))
    draw = ImageDraw.Draw(image)

    r, g, b =(0, 255, 255)
    
    offset_left = 0
    

    draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))
    #draw.text((text_x + offset_left, text_y), text, font=font)

    offset_left += font.getsize(text)[0] + width

    for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

        unicornhathd.show()
        time.sleep(0.01)


    T = bme280.get_temperature()
    T = round(T)
          
    if T <= 0: 
        r, g, b = [0, 0, 255]    # Blue
        text = ("and its very Cold @ %sc") % (T)
    elif T > 0 and T < 13:
        r, g, b, = [255, 255, 0] # Yellow
        text = ("and its cool at %sc") % (T)
    elif T >= 13 and T < 25:
        r, g, b = [0, 255, 0]    # Green
        text = ("and the Temperature is %sc") % (T)
    elif T >= 25 and T < 30:
        r, g, b = [255, 50, 0]  # Orange
        text = ("and its Hot @ %sc") % (T)
    elif T >= 30:
        r, g, b = [255, 0, 0]    # Red
        text = ("and its very Hot @ %sc") % (T)

    width, height = unicornhathd.get_shape()

    text_x = width
    text_y = 2


    font_file, font_size = FONT

    font = ImageFont.truetype(font_file, font_size)

    text_width, text_height = width, 0
        
    w, h = font.getsize(text)
    text_width += w + width
    text_height = max(text_height, h)

    
    image = Image.new('RGB', (text_width, max(16, text_height)), (0, 0, 0))
    draw = ImageDraw.Draw(image)
   
    offset_left = 0
    

    draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))
    #draw.text((text_x + offset_left, text_y), text, font=font)

    offset_left += font.getsize(text)[0] + width

    for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

        unicornhathd.show()
        time.sleep(0.01)


    H = bme280.get_humidity() 
    H = round(H)

    if H < 30:
        r, g, b = [255, 0, 0]    # Red
        text = ("with Low %s%% Humidity") % (H)
    elif H >= 30 and H <= 60:
        r, g, b = [0, 255, 0]    # Green
        text = ("with %s%% Humidity") % (H)
    elif H > 60 and H < 80:
        r, g, b = [255, 255, 0]  # Yellow
        text = ("with High %s%% Humidity") % (H)
    elif H >= 80:
        r, g, b = [255, 0, 0]    # Red
        text = ("with Very High %s%% Humidity") % (H)

    width, height = unicornhathd.get_shape()

    text_x = width
    text_y = 2


    font_file, font_size = FONT

    font = ImageFont.truetype(font_file, font_size)

    text_width, text_height = width, 0
        
    w, h = font.getsize(text)
    text_width += w + width
    text_height = max(text_height, h)

    
    image = Image.new('RGB', (text_width, max(16, text_height)), (0, 0, 0))
    draw = ImageDraw.Draw(image)
   
    offset_left = 0
    

    draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))
    #draw.text((text_x + offset_left, text_y), text, font=font)

    offset_left += font.getsize(text)[0] + width

    for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

        unicornhathd.show()
        time.sleep(0.01)

    p = bme280.get_pressure() 
    P = round(p)
            
    if P > 0 and P < 982:             # Very Low
        r, g, b = [255, 0, 0]         # Red
        text = ("Baromiter is Very Low@ %smb : Storm Watch") % (P)
    elif P >= 982 and P < 1004:       # Low
        r, g, b = [255, 255, 0]       # Yellow
        text = ("Barometer is Low @ %smb : Posible Precipitation") % (P)
    elif P >= 1004 and P < 1026:      # Mid Range
        r, g, b = [0, 255, 0]         # Green
        text = ("Barometer is @ %smb") % (P)
    elif P >= 1026 and P < 1048:      # High
        r, g, b = [0, 0, 255]         # Blue
        text = ("Barometer is High @ %smb") % (P)
    elif P >= 1048:                   # Very High
        r, g, b = [255, 50, 0]        # Orange
        text = ("Barometer is Very High @ %smb") % (P)


    width, height = unicornhathd.get_shape()

    text_x = width
    text_y = 2


    font_file, font_size = FONT

    font = ImageFont.truetype(font_file, font_size)

    text_width, text_height = width, 0
        
    w, h = font.getsize(text)
    text_width += w + width
    text_height = max(text_height, h)

    
    image = Image.new('RGB', (text_width, max(16, text_height)), (0, 0, 0))
    draw = ImageDraw.Draw(image)
   
    offset_left = 0
    

    draw.text((text_x + offset_left, text_y), text, font=font, fill=(r, g, b))
    #draw.text((text_x + offset_left, text_y), text, font=font)

    offset_left += font.getsize(text)[0] + width

    for scroll in range(text_width - width):
        for x in range(width):
            for y in range(height):
                pixel = image.getpixel((x + scroll, y))
                r, g, b = [int(n) for n in pixel]
                unicornhathd.set_pixel(width - 1 - x, y, r, g, b)

        unicornhathd.show()
        time.sleep(0.01)

You’re welcome, it sounds great! It’s always satisfying when you finally get something working the way you want it.

Yes, very satisfying. It nice to have finally done something with my Unicorn HD. I’ve had it for a while now just sitting in a box doing nothing.