Adjust Python examples

I added one of these to my Unicorn Mimi

And changed rotation = 180 so the little feet are down and the power jack is pointing up.

I didn’t use the screws that came with it, too skinny and won’t skrrew into a stock standoff?
I used my own long standard screws with a nut between it and the unicornmini.
You can add text to the message if you want.
text = time.strftime(“It’s %A %B %-d %-I:%M%p”)

@placebo83 If you compare my file to that original scroll Hat Mini clock.py file, you may be able to modify mine to have the static. 12:00 you were originally after.
I’m thinking its the

for y in range(display_height):
        for x in range(display_width):
            if image.getpixel((x + offset_x, y)) == 255:

That makes it scroll across the screen.

Also have the pHAT Diffuser for it too, screws that came with it were also working find enough for me. The Pi Zero WH is in a Pibow. BTW does someone know a good diffuser for the Ubercorn? I also set rotation = 180. I leave the scroll in it, maybe do something color wise but that would be it for now :)

The line that sets the color is below. It’s set to green in my code.

if image.getpixel((x + offset_x, y)) == 255:
                unicornhatmini.set_pixel(x, y, 0, 255, 0)

unicornhatmini.set_pixel(x, y, 255, 255, 0) would be yellow.

I also changed my brightness to 0.5 after I posted my code
unicornhatmini.set_brightness(0.5)

I changed it to blue with 0, 0, 255.
The only error I get after a few minutes (sometimes after the 2nd time the date and time comes, sometimes not even after 5 times) is:

17x7
Traceback (most recent call last):
File “./textclock.py”, line 64, in
if image.getpixel((x + offset_x, y)) == 255:
File “/usr/local/lib/python3.7/dist-packages/PIL/Image.py”, line 1343, in getpixel
return self.im.getpixel(xy)
IndexError: image index out of range

The script stops after that, I can restart it without problems but the error keeps coming back.

I just went and had a look at mine, its also stopped with that same error?
I have no idea what it means though? Mine was still running about 10 minutes ago and was running for quit a while. I’ll see if I can figure out what that means?

If I have time I’ll also try to find where it goes wrong, but for nor already really happy with my small clock!

My best guess is its trying to set a pixel (led) outside of the 7 x 17 range.
Which is I believe rows 0 to 6 for x, and columns 0 to 16 for y.
I’m running mine with
text = time.strftime("%A %B %-d %-I:%M:%p")
and its been going for 30 minutes with no error.

I made it 5:01PM and it errored out. I’m going to clip and past the error message to a text file so i can research it.

Traceback (most recent call last):
  File "/home/pi/mini_clock.py", line 64, in <module>
    if image.getpixel((x + offset_x, y)) == 255:
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 1333, in getpixel
    return self.im.getpixel(xy)
IndexError: image index out of range

I have some new code to test. I have a hunch as to what might be happening.
With the old code the text / image was being written to the buffer over and over while it was simultaneously being read out and displayed. Which I think corrupted the saved image.
With this code the text= and draw image only happens just before it starts to show the message. And doesn’t get updated again until the end when it starts over. I’m hoping that’s what’s happening, its running now on mine and keeping correct time.
It should, save date time > display date and time > update date and time > display date and time > etc.

#!/usr/bin/env python3
import time, datetime
import sys

from PIL import Image, ImageDraw, ImageFont
from unicornhatmini import UnicornHATMini

unicornhatmini = UnicornHATMini()

rotation = 180
if len(sys.argv) > 1:
    try:
        rotation = int(sys.argv[1])
    except ValueError:
        print("Usage: {} <rotation>".format(sys.argv[0]))
        sys.exit(1)

unicornhatmini.set_rotation(rotation)
display_width, display_height = unicornhatmini.get_shape()

print("{}x{}".format(display_width, display_height))

unicornhatmini.set_brightness(0.5)

font = ImageFont.truetype("5x7.ttf", 8)

offset_x = 0

while True:

    if offset_x == 0:
        text = time.strftime("%A %B %-d %-I:%M %p")
        text_width, text_height = font.getsize(text)
        image = Image.new('P', (text_width + display_width + display_width, display_height), 0)
        draw = ImageDraw.Draw(image)
        draw.text((display_width, -1), text, font=font, fill=255)
    else:
        
        for y in range(display_height):
            for x in range(display_width):
                if image.getpixel((x + offset_x, y)) == 255:
                    unicornhatmini.set_pixel(x, y, 0, 255, 0)
                else:
                    unicornhatmini.set_pixel(x, y, 0, 0, 0)

    offset_x += 1
    if offset_x + display_width > image.size[0]:
        offset_x = 0

    unicornhatmini.show()
    time.sleep(0.05)

EDIT: So far so good, its been running since about 10:30 AM this morning and its now 3 PM with no issues. I’m going to leave it running until I hit the sack tonight for further testing.

EDIT:2 Forum software won’t let me do more than three posts in a row.

New code with shutdown via the X button. Button A set global brightness to 0.5 and the B button sets it to 1.0

 #!/usr/bin/env python3
import sys
import os
import time, datetime
import RPi.GPIO as GPIO

from PIL import Image, ImageDraw, ImageFont
from unicornhatmini import UnicornHATMini

unicornhatmini = UnicornHATMini()

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(6, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)

# button_map
#  5: "A",
#  6: "B",
# 16: "X",
# 24: "Y"}

X = 0



def Dim(channel):  
    unicornhatmini.set_brightness(0.5)

def Bright(channel):  
    unicornhatmini.set_brightness(1.0)

def Shutdown(channel):  
    global X
    X = 1    

GPIO.add_event_detect(5, GPIO.FALLING, callback = Dim, bouncetime = 2000)
GPIO.add_event_detect(6, GPIO.FALLING, callback = Bright, bouncetime = 2000)
GPIO.add_event_detect(16, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

rotation = 180
if len(sys.argv) > 1:
    try:
        rotation = int(sys.argv[1])
    except ValueError:
        print("Usage: {} <rotation>".format(sys.argv[0]))
        sys.exit(1)

unicornhatmini.set_rotation(rotation)
display_width, display_height = unicornhatmini.get_shape()

unicornhatmini.set_brightness(0.5)

font = ImageFont.truetype("5x7.ttf", 8)

offset_x = 0

while True:

    if offset_x == 0:
        text = time.strftime("%A %B %-d %-I:%M %p")
        text_width, text_height = font.getsize(text)
        image = Image.new('P', (text_width + display_width + display_width, display_height), 0)
        draw = ImageDraw.Draw(image)
        draw.text((display_width, -1), text, font=font, fill=255)
    else:
        
        for y in range(display_height):
            for x in range(display_width):
                if image.getpixel((x + offset_x, y)) == 255:
                    unicornhatmini.set_pixel(x, y, 0, 255, 0)
                else:
                    unicornhatmini.set_pixel(x, y, 0, 0, 0)

    offset_x += 1
    if offset_x + display_width > image.size[0]:
        offset_x = 0

    if X == 1:
        unicornhatmini.set_all(0, 0, 0)
        unicornhatmini.show()
        os.system("sudo shutdown now -P")
        time.sleep(30)

    unicornhatmini.show()
    time.sleep(0.05)

# Last edited on June 6th 2020
# added shutdown via button X
# also added Dim and Bright function to button A and B
# run sudo crontab -e
# add
# @reboot python3 /home/pi/scroll_clock.py &

1 Like

Nice script, works also on mine although it’s hard to squeeze under the diffuser to press the buttons.

I’m going to drill some small holes in mine, right over the buttons. Then use a toothpick to press them. I have some nice round wooden ones that don’t break easily. That’s my plan anyway.

I saw this in the image.py example
unicornhatmini.set_image(image, offset_y=offset_y, wrap=True)
If we can figure out where to put the wrap=True I’m thinking it will get rid of that black dead space at the end of one message just before it goes again.
unicornhatmini.set_image(wrap=True) might be all that’s needed.

EDIT: looks like it should be unicornhatmini.set_image(image, wrap=True)
I found a spot where I didn’t get any errors but it didn’t appear to do anything?
That might just be because of the way the other code renders the message?

If you change

def Dim(channel):  
    unicornhatmini.set_brightness(0.5)

def Bright(channel):  
    unicornhatmini.set_brightness(1.0)

to

def Dim(channel):  
    global B
    B = B - 0.1

    if B <= 0.1:
        B = 0.1

    unicornhatmini.set_brightness(B)

def Bright(channel):  
    global B
    B = B + 0.1

    if B >= 1.0:
        B = 1.0

    unicornhatmini.set_brightness(B)  

You will get incremental brightness adjustment from 0.1 to 1.0.

You will also have to add a
B = 0.5 to set the default
And change
unicornhatmini.set_brightness(0.2)
to
unicornhatmini.set_brightness(B)

I think that’s all the changes I made. If you try it and get errors I’ll post the whole working file.

I don’t get an error, but the buttons don’t work either :/

Ok I must have missed something else I changed?
Here is the full file I just pulled off of that Pi, buttons working for me.
You’ll have to fix the path to the font file so crontab will work. ;)

 #!/usr/bin/env python3
import sys
import os
import time, datetime
import RPi.GPIO as GPIO

from PIL import Image, ImageDraw, ImageFont
from unicornhatmini import UnicornHATMini

unicornhatmini = UnicornHATMini()

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_UP)  # A
GPIO.setup(6, GPIO.IN, pull_up_down = GPIO.PUD_UP)  # B
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP) # X
#GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP) # Y

# button_map
#  5: "A",
#  6: "B",
# 16: "X",
# 24: "Y"}

X = 0
Y = 0
B = 0.5

def Dim(channel):  
    global B
    B = B - 0.1

    if B <= 0.1:
        B = 0.1

    unicornhatmini.set_brightness(B)

def Bright(channel):  
    global B
    B = B + 0.1

    if B >= 1.0:
        B = 1.0

    unicornhatmini.set_brightness(B)  

def Shutdown(channel):  
    global X
    X = 1

#def Exit(channel):  
#    global Y
#    Y = 1       

GPIO.add_event_detect(5, GPIO.FALLING, callback = Dim, bouncetime = 2000)
GPIO.add_event_detect(6, GPIO.FALLING, callback = Bright, bouncetime = 2000)
GPIO.add_event_detect(16, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)
#GPIO.add_event_detect(24, GPIO.FALLING, callback = Exit, bouncetime = 2000)

rotation = 180
if len(sys.argv) > 1:
    try:
        rotation = int(sys.argv[1])
    except ValueError:
        print("Usage: {} <rotation>".format(sys.argv[0]))
        sys.exit(1)

unicornhatmini.set_rotation(rotation)
display_width, display_height = unicornhatmini.get_shape()

#print("{}x{}".format(display_width, display_height))

unicornhatmini.set_brightness(B)

font = ImageFont.truetype("/home/pi/5x7.ttf", 8)

offset_x = 0

while True:

    if offset_x == 0:
        text = time.strftime("%A %B %-d %-I:%M %p")
        text_width, text_height = font.getsize(text)
        image = Image.new('P', (text_width + display_width + display_width, display_height), 0)
        draw = ImageDraw.Draw(image)
        draw.text((display_width, -1), text, font=font, fill=255)
    else:
        
        for y in range(display_height):
            for x in range(display_width):
                if image.getpixel((x + offset_x, y)) == 255:
                    unicornhatmini.set_pixel(x, y, 0, 0, 255)
                else:
                    unicornhatmini.set_pixel(x, y, 0, 0, 0)

    offset_x += 1
    if offset_x + display_width > image.size[0]:
        offset_x = 0

    if X == 1:
        unicornhatmini.set_all(0, 0, 0)
        unicornhatmini.show()
        os.system("sudo shutdown now -P")
        time.sleep(30)

    if Y == (1):
        unicornhatmini.set_all(0, 0, 0)
        unicornhatmini.show()        
        raise SystemExit
        time.sleep(30)        

    unicornhatmini.show()
    time.sleep(0.05)
    
# Last edited on June 12th 2020
# added shutdown via button X
# also added Dim and Bright function to button A and B
# run sudo crontab -e
# add
# @reboot python3 /home/pi/scroll_clock.py &

1 Like

Just so we are both on the same page,
pressing and holding the button down won’t increment the value more than 0.1.
It’s repeated presses, each one press changing it by 0.1.
I don’t know how to code it for a hold down function.

You’d have to change the “Falling” in
GPIO.add_event_detect(5, GPIO.FALLING, callback = Dim, bouncetime = 2000)

FALLING is Button Pressed. Has to be released to be detected a second time.
RISING is Button Released.

Had to change some minor parts, so probably the problem was something there. Yeah I got that it are repeated presses :)

For me it usually goes as follows.
Have an idea for a change, and change the code to what I think will work.
Run the new code “noting the errors” lol, then fix them one by one until it runs.
Then forget all the changes you made along the way to getting it to work. ;)
Save the new file (and old file) so the changes don’t get lost. =)

I also switched to Blue text. I have to say it does look nice, especially in a dark or dimly lighted room.
I have a what I call a Weather Clock setup based on a Pi A+, Sense Hat and assorted environmental sensors. It displays the Day, Date, Time, Temperature, Humidity, Barometric Pressure and UV index in a continuously scrolling message on the Sense Hats 8 x 8 RGB LED matrix. Much like what we are doing on the Unicorn Mini.
Each separate element changes color based on conditions. The temperature text is Blue if the temp is 0c or lower for example.
I also check the ambient light and adjust the brightness based on the background light level. In dark conditions the display is dimmed, in sunlight its full bright, and in very bright sunlight I change all the text to white so I can read it. I have hard time reading Blue and Red text in very bright sunlight. Red Green color deficiency.
My next plan is to hook my Unicorn Mini up with my Breakout Garden Mini and a BME280, and replicate some of what I did on my weather clock.