Die perfekte Ergänzung zur DIY Wake-Up Lampe ist natürlich eine Uhr.
Mit einem 32×8 LED-Dot-Matrix-Display für nicht mal 10 Euro kannst Du nicht nur eine schöne Uhr realisieren, sondern auch eine Laufschrift, mit der Informationen jeglicher Art darstellgestellt werden können. In meinem kleinen Beispiel nutze ich den Ticker, um das Datum, aktuelle Nachrichten oder meinen YouTube Abonnenten Counter anzuzeigen.
Für die Ansteuerung der LED Matrix verwende ich die Bibliothek luma.led_matrix.
Jedes 8×8 Segment der LED-DotMatrix wird durch einen MAX7219 IC angesteuert. Dafür muss beim Raspberry Pi die SPI Schnittstelle aktiviert werden. Das geht durch Ausruf von
sudo raspi-config
Dort kann die SPI Schnittstelle im folgenden Menü aktiviert werden:
3 Interfacing Options
P4 SPI
Die luma.led_matrix Bibliothek benötigt außerdem einige andere Bibliotheken, von denen einige bereits auf dem Raspberry Pi vorinstalliert sein sollten:
sudo apt install build-essential sudo apt install python3-dev sudo apt install python3-pip sudo apt install libfreetype6-dev sudo apt install libjpeg-dev sudo apt install libopenjp2-7 sudo apt install libtiff5
Die Installation der verwendeten Bibliothek luma.led_matrix auf dem Raspberry Pi und der Download des Sourcecodes, der auch das Beispiel enthält, erfolgt mit:
sudo -H pip3 install --upgrade luma.led_matrix
git clone https://github.com/rm-hull/luma.led_matrix luma.led_matrix

Mit dem Source Code kommt auch das Beispiel „silly_clock“ von ttsiodras, welches mir als Inspiration für meine Uhr gedient hat. Meine Implementierung MyClock.py ist aber vollständig neu coderit und hat ein paar grundlegende Änderungen:
- geänderte Ausrichtung: Stunden rechtsbündig zum Doppelpunkt ausgerichtet und Minuten Linksbündig zum Doppelpunkt ausgerichtet
- Rollenzähler Animation für Stunden und Minuten
- Ausführung in einem eigenen Thread, aus einem Hauptprogramm zum Beispiel LED-Strip und LED-Matrix Display gleichzeitig angesteuert werden können
- Interface für die Anzeige einer beliebigen Laufschrift
- Interface zum ausschalten der Uhr (z.B. Nachts)

Hier der Source Code für RollingClock.py:
#!/usr/bin/env python3
# RollingClock by joe703 / https://www.youtube.com/channel/UChMi8gAr52_jZXIpr9WXYQQ
# Inspired by luma.led_matrix/examples/silly_clock.py by ttsiodras
# https://github.com/rm-hull/luma.led_matrix/blob/master/examples/silly_clock.py
import threading
import time
from datetime import datetime
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.render import canvas
from luma.core.legacy import text, show_message
from luma.core.legacy.font import proportional, CP437_FONT, TINY_FONT
class RollingClock(threading.Thread):
def __DrawNumber(self, draw, StringOld, StringNew, PosOld, PosNew, Iterator):
# Draws and animates Number - Iterator has to be increased from 0 (old String) to 8 (NewString)
if Iterator > 8:
Iterator = 8
if Iterator < 8:
text(draw, (PosOld, 1 - Iterator), StringOld, fill="white", font=proportional(CP437_FONT))
if Iterator > 0:
text(draw, (PosNew, 9 - Iterator), StringNew, fill="white", font=proportional(CP437_FONT))
def __DrawColon(self, draw, StringOld, StringNew, Iterator):
# Draws and animates colon - Iterator has to be increased from 0 (old String) to 8 (NewString)
if StringOld == ":":
text(draw, (15, 1 - Iterator), ":", fill="white", font=proportional(TINY_FONT))
if StringNew == ":":
text(draw, (15, 9 - Iterator), ":", fill="white", font=proportional(TINY_FONT))
def __GetHourPos(self, hours):
# Returns position for hours with CP437_FONT
if hours == 0 or hours == 4:
return 7
elif hours < 10:
return 8
elif hours == 10 or hours == 14 or hours == 20:
return 0
else:
return 1
def __init__(self):
# Init Own Thread for Clock
threading.Thread.__init__(self)
# Init LED Matrix
serial = spi(port=0, device=0, gpio=noop())
self.device = max7219(serial, cascaded=4, block_orientation=90, blocks_arranged_in_reverse_order=True)
self.device.contrast(16)
def run(self):
# Clock is running
self.__RunClock = True
self.__ShowClock = True
self.__DisplayText=""
# Toggle the second indicator every second
toggle = False
while self.__RunClock:
# Init Time
CurrentTime = datetime.now()
MinutesStr = CurrentTime.strftime('%M')
MinutesStrOld = MinutesStr
HoursStr = CurrentTime.strftime('%-H')
HoursStrOld = HoursStr
HoursPos = self.__GetHourPos(CurrentTime.hour)
HoursPosOld = HoursPos
# Scroll in Clock
for i in range(0,9):
with canvas(self.device) as draw:
self.__DrawNumber(draw, "", HoursStr, HoursPos, HoursPos, i)
self.__DrawColon(draw, "", ":", i)
self.__DrawNumber(draw, "", MinutesStr, 17, 17, i)
time.sleep(0.1)
while (self.__ShowClock==True and self.__DisplayText==""):
# Get New Time
CurrentTime = datetime.now()
MinutesStr = CurrentTime.strftime('%M')
HoursStr = CurrentTime.strftime('%-H')
HoursPos = self.__GetHourPos(CurrentTime.hour)
# Handle special cases for right alignemnt of hours in CP437_FONT
HoursPos = self.__GetHourPos(CurrentTime.hour)
if (MinutesStr != MinutesStrOld or HoursStr != HoursStrOld):
# Time changed
for i in range(0,9):
if i == 5:
# toggle colon
toggle = not toggle
if HoursStr != HoursStrOld:
# Animate Hours and Minutes
with canvas(self.device) as draw:
self.__DrawNumber(draw, HoursStrOld, HoursStr, HoursPosOld, HoursPos, i)
self.__DrawColon(draw, ":" if toggle else " ", " ", 0)
self.__DrawNumber(draw, MinutesStrOld, MinutesStr, 17, 17, i)
elif MinutesStr[0] != MinutesStrOld[0]:
# Animate 2 digit Minute Update
with canvas(self.device) as draw:
self.__DrawNumber(draw, HoursStrOld, HoursStr, HoursPos, HoursPos, 0)
self.__DrawColon(draw, ":" if toggle else " ", " ", 0)
self.__DrawNumber(draw, MinutesStrOld, MinutesStr, 17, 17, i)
else:
# Animate 1 digit Minute Update
with canvas(self.device) as draw:
self.__DrawNumber(draw, HoursStrOld, HoursStr, HoursPos, HoursPos, 0)
self.__DrawColon(draw, ":" if toggle else " ", " ", 0)
self.__DrawNumber(draw, MinutesStr[0],
MinutesStr[0], 17, 17, 0)
# If we don't draw digit 1 we need to check it for the position
if MinutesStr[0] == "0" or MinutesStr[0] == "4":
self.__DrawNumber(draw, MinutesStrOld[1], MinutesStr[1], 25, 25, i)
else:
self.__DrawNumber(draw, MinutesStrOld[1], MinutesStr[1], 24, 24, i)
time.sleep(0.1)
else:
# Redraw Time to toggle colon
with canvas(self.device) as draw:
self.__DrawNumber(draw, HoursStr, HoursStr, HoursPos, HoursPos, 0)
self.__DrawColon(draw, ":" if toggle else " ", " ", 0)
self.__DrawNumber(draw, MinutesStr, MinutesStr, 17, 17, 0)
time.sleep(0.5)
# Store Time
MinutesStrOld = MinutesStr
HoursStrOld = HoursStr
HoursPosOld = HoursPos
# toggle colon
toggle = not toggle
# Scroll out Clock
for i in range(0,9):
with canvas(self.device) as draw:
self.__DrawNumber(draw, HoursStr, "", HoursPos, HoursPos, i)
self.__DrawColon(draw, ":", "", i)
self.__DrawNumber(draw, MinutesStr, "", 17, 17, i)
time.sleep(0.1)
# Wait and show text
while self.__RunClock and ((self.__ShowClock==False) or (self.__DisplayText!="")):
if self.__DisplayText!="":
show_message(self.device, self.__DisplayText, fill="white", font=proportional(CP437_FONT))
self.__DisplayText=""
time.sleep(0.5)
def Show(self):
self.__ShowClock = True
def Hide(self):
self.__ShowClock = False
def ShowText(self, text):
# Replace special characters, whch are not available in font
chars = {'ö':'oe','ä':'ae','ü':'ue','Ö':'Oe','Ä':'Ae','Ü':'ue','ß':'ss'}
for char in chars:
text = text.replace(char,chars[char])
# Check if text can be displayed and request output if not busy
if self.__DisplayText=="":
self.__DisplayText = text
print("Textausgabe angefordert: "+text)
return True
else:
print("Textausgabe nicht moeglich: "+text)
return False
def close(self):
self.__ShowClock = False
self.__RunClock = False
if __name__ == "__main__":
Wochentag=["Sonntag ", "Montag ", "Dienstag ", "Mittwoch ", "Donnerstag ", "Freitag ", "Samstag "]
# Main for Test
Uhr = RollingClock()
Uhr.start()
print("Uhr gestartet")
print("Press Ctrl-C to quit.")
try:
while True:
datum = datetime.now().strftime('%d.%m.%Y')
tag = datetime.now().strftime('%w')
sekunden = datetime.now().strftime('%S')
if sekunden=="05":
# show Date
Uhr.ShowText(Wochentag[int(tag)] + datum)
time.sleep(1)
except KeyboardInterrupt:
pass
Uhr.close()
print("Stop der Uhr angefordert")
Uhr.join()
print("Uhr gestoppt")
Mit start() wird der Thread und die Uhr gestartet. Mit Hide() wird die Uhr ausgeschaltet (Anzeige der Laufschrift ist weiter möglich) und mit Show() wieder eingeschaltet. Mit ShowText() kann ein Text als Laufschrift angezeigt werden. Mit close() wird der Thread und die Uhr beendet.
Mit dem folgenden Python Script wird die RollingClock aufgerufen und es werden verschiedene Informationen als Laufschrift angezeigt. Zum parsen von RSS Dateien (und vielen anderen Formaten) verwende ich feedparser. Feedparser wird mit
pip3 install feedparser
installiert.
Google stellt Basis Informationen für den Youtube Kanal als JSON-File zur Verfügung. Für den YouTube Abonnenten Counter sind „___YOUTUBE-KANAL-ID___“ und „___GOOGLE-API-KEY___“ durch die Kanal ID des YouTube Kanals mit dem zugehörigen API-Key und „Joe 703 / raspberry.py“ durch den Kanalnamen zu ersetzen.
Hier der Source Code für RollingClockTicker.py, meiner Beispielimplementierung für einen Newsticker mit Schlagzeilen von Tagesschau.de und einem YouTube Abonnenten Counter.
#!/usr/bin/env python3
# RollingClockTicker by joe703 / https://www.youtube.com/channel/UChMi8gAr52_jZXIpr9WXYQQ
import time
from datetime import datetime
import json, urllib.request
import feedparser
import RollingClock
def ReadYoutubeSubscriberCounter():
try:
url = "https://www.googleapis.com/youtube/v3/channels?part=statistics&id=___YOUTUBE-KANAL-ID___&key=___GOOGLE-API-KEY___"
res = urllib.request.urlopen(url).read().decode('utf-8')
data = json.loads(res)
SubscriberText = data['items'][0]['statistics']['subscriberCount']
except:
SubscriberText = "???"
return "Joe 703 / raspberry.py: " + SubscriberText + " Abonnenten"
def ReadNews():
try:
NewsFeed = feedparser.parse("https://www.tagesschau.de/xml/rss2_https/")
NewsText = NewsFeed.entries[0].title+": "+NewsFeed.entries[0].content[1].value
except:
NewsText = "Keine News ???"
return NewsText
if __name__ == "__main__":
Wochentag=["Sonntag ", "Montag ", "Dienstag ", "Mittwoch ", "Donnerstag ", "Freitag ", "Samstag "]
OldNewsText=""
OldSubscriberText=""
# Main for Test
Uhr = RollingClock.RollingClock()
Uhr.start()
print("Uhr gestartet")
print("Press Ctrl-C to quit.")
try:
while True:
datum = datetime.now().strftime('%d.%m.%Y')
tag = datetime.now().strftime('%w')
sekunden = datetime.now().strftime('%S')
if sekunden=="05":
# show Youtube Subscriber Counter if changed
SubscriberText = ReadYoutubeSubscriberCounter()
if SubscriberText != OldSubscriberText:
if Uhr.ShowText(SubscriberText):
OldSubscriberText=SubscriberText
# show feed if changed
NewsText = ReadNews()
if NewsText != OldNewsText:
if Uhr.ShowText(NewsText):
OldNewsText=NewsText
# show Date (if not busy with showing something else)
Uhr.ShowText(Wochentag[int(tag)] + datum)
time.sleep(1)
except KeyboardInterrupt:
pass
Uhr.close()
print("Stop der Uhr angefordert")
Uhr.join()
print("Uhr gestoppt")
Youtube Video
Das Video dazu auf meinem YouTube-Kanal:
Raspberry Pi Tutorial – LED-Matrix Uhr
Amazon Links
*Werbung! Wenn Du auf einen der Amazon Links klickst und anschließend ein beliebiges Produkt auf Amazon kaufst, unterstützt Du meine Seite mit einem kleinen Anteil. Dir entstehen dadurch KEINE Mehrkosten und Du zahlst den ganz normalen Preis. Danke!
LED Dot Matrix Display
MAX7219 8×32 Dot Matrix LED Anzeigemodul – https://amzn.to/3izeRiG
Raspberry Pi 3
Raspberry Pi 3 Model B – https://amzn.to/3o5kWou
Netzteil 3A mit Schalter – https://amzn.to/3pcK6D2
Alternativ: Raspberry Pi 3 Starter Kit
Raspberry Pi 3 Model B Starter Kit inkl. SD-Karte vorinstalliert mit Raspbian OS – https://amzn.to/2M9Zt0b
Raspberry Pi Zubehör
Raspberry Pi Gehäuse – https://amzn.to/399Te5P
16GB microSD Karte – https://amzn.to/2KAdzaK
Steckbrett (3 Stück) – https://amzn.to/3pjimN7
Super gemacht , vor allem wurden die Verbesserungen schön erklärt !
Vielleicht gibt es bald ein Portierung auf das Raspberry PI PICO ?