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 ?