Unicorn Mini Scrolling Clock code I came up with

I just recently got my first Unicorn Mini and had some fun coding on it, and want to share what I came up with. The main code is borrowed from the GitHub examples and modified by me.
The Day, Date and Time are shown in a continuously scrolling repeating message. The information is updated each time the message displays.
text = time.strftime("%A %B %-d %-I:%M %p")
https://strftime.org/
The X button is programed to do a proper shutdown when Pressed.
The Y button cycles through color options set by the following lines.

 if Y == 0:
        r, g, b = (0, 255, 255)   # Aqua
    elif Y == 1:
        r, g, b = (255, 0, 0)     # Red 
    elif Y == 2:
        r, g, b = (0, 205, 0)     # Green
    elif Y == 3:
        r, g, b = (0, 0, 255)     # Blue  
    elif Y == 4:
        r, g, b = (255, 140, 0)   # Orange

Changing the numbers in brackets changes the colors assigned.
The Y= line above the while true sets the default color, Y = 0 is Aqua.

Pressing the A button will dim the display slightly each time its pressed.
Pressing the B button will brighten it slightly each time its pressed.
The B = line sets the default brightness. It goes from 0 to 1 in increments of 0.1.

I have the pHat diffuser on mine and have rotated the display 180.
rotation = 180, change it to rotation = 0 to get it back to right side up.

There is a 5x7.ttf font file that has to be in the same folder as this python script for this to work. I got that file from the examples folder. It’s the same file the text.py example file uses. If you want to run this file on bootup with crontab, you need to add the full path to this line.
font = ImageFont.truetype("5x7.ttf", 8)
for me its
font = ImageFont.truetype("/home/pi/5x7.ttf", 8)
and my crontab entry is
@reboot python3 /home/pi/scroll_clock.py

It’s not obvious unless you look for it but there is another color option after Orange that IMHO is pretty cool. Just keep pressing the Y button to get to it.

And finally my code. =)

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

from colorsys import hsv_to_rgb

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

X = 0
Y = 0
B = 0.3

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 color(channel):  
    global Y
    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 = color, 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(B)

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

offset_x = 0

while True:

    if Y > 5:
        Y = 0

    if Y == 0:
        r, g, b = (0, 255, 255)   # Aqua
    elif Y == 1:
        r, g, b = (255, 0, 0)     # Red 
    elif Y == 2:
        r, g, b = (0, 205, 0)     # Green
    elif Y == 3:
        r, g, b = (0, 0, 255)     # Blue  
    elif Y == 4:
        r, g, b = (255, 140, 0)   # Orange

    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)

    if Y == 5:
        
        for y in range(display_height):
            for x in range(display_width):
                hue = (time.time() / 10.0) + (x / float(display_width * 2))
                r, g, b = [int(c * 255) for c in hsv_to_rgb(hue, 1.0, 1.0)]
                if image.getpixel((x + offset_x, y)) == 255:
                    unicornhatmini.set_pixel(x, y, r, g, b)
                else:
                    unicornhatmini.set_pixel(x, y, 0, 0, 0)
    if Y < 5:           

        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, r, g, b)
                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)
1 Like