Seite im Aufbau Tools schon nutzbar

Projekt 01 · Raspberry Pi & E-Paper

Wochenkalender
auf E-Ink.

Ein Raspberry Pi holt deine Termine aus Google Kalender und zeigt sie auf einem 7,3-Zoll-E-Paper-Display in sieben Farben an. Der laufende oder nächste Termin ist hervorgehoben, jeder Kalender hat seine eigene Farbe – und ohne Strom bleibt das Bild stehen.

2–3 Std.Zeitbedarf
MittelSchwierigkeit
14Kapitel
keineVorkenntnisse
Wochenansicht auf dem E-Paper-Display: fünf Tagesspalten mit farbig markierten Terminen, der laufende Termin ist grün hervorgehoben
800 × 480 Pixel · sieben Farben · Bild bleibt ohne Strom stehen
Projektdateien (ZIP, ca. 100 KB)

Alle Programmdateien, die Beispielkonfiguration und die systemd-Dateien. Wird in Kapitel 7 benötigt.

Laden

Diese Anleitung setzt keine Programmierkenntnisse voraus. Jeder Befehl steht in einem eigenen Kasten, darunter steht in normalem Deutsch, was er bewirkt. Wer nur nachbauen will, arbeitet die Kapitel der Reihe nach ab.

01 Was du brauchst

Teil Bemerkung
Raspberry Pi 3B+ oder neuer Getestet auf 3B+. Ein Zero 2 W geht auch, ist aber langsamer.
Waveshare 7.3" e-Paper HAT (F) Das 7-Farben-Modell (ACeP), 800 × 480 Pixel
microSD-Karte 16 GB genügen
Netzteil Offizielles Pi-Netzteil, 2,5 A
Bilderrahmen oder Gehäuse Optional, aber macht viel aus

Achte beim Kauf auf das Kürzel (F) in der Produktbezeichnung. Waveshare verkauft mehrere 7,3-Zoll-Displays: (E) und (G) haben andere Farben und brauchen einen anderen Treiber. Nur (F) hat die sieben Farben Schwarz, Weiss, Rot, Gelb, Grün, Blau und Orange.

Ein HAT wird einfach auf die 40-polige Stiftleiste des Pi gesteckt. Löten oder Verkabeln ist nicht nötig.

02 Das Display kennenlernen

Bevor du loslegst: E-Paper funktioniert anders als ein Bildschirm, und ein paar Eigenheiten bestimmen den ganzen Aufbau.

Ein Bildwechsel dauert 35 Sekunden. Das Display baut sich dabei sichtbar in mehreren Farbdurchgängen auf und flackert. Das ist normal und kein Defekt.

Zwischen zwei Bildwechseln müssen mindestens 3 Minuten liegen. Häufigere Aktualisierung schadet dem Panel.

Das Panel darf nicht dauerhaft unter Spannung stehen. Nach jedem Bildwechsel muss es in den Schlafmodus geschickt werden. Das Programm in dieser Anleitung erledigt das automatisch, und zwar auch dann, wenn zwischendurch ein Fehler auftritt. Wer das selbst programmiert und diesen Punkt übersieht, riskiert einen dauerhaften Schaden am Display.

Mindestens einmal pro Tag sollte das Bild erneuert werden, sonst brennt es sich ein.

Betriebstemperatur 15 bis 35 Grad. In einem kalten Wintergarten arbeitet das Display nicht zuverlässig.

Ohne Strom bleibt das Bild stehen. Du kannst den Pi abends ausschalten – der Kalender bleibt lesbar.

03 Raspberry Pi vorbereiten

Installiere Raspberry Pi OS mit dem Raspberry Pi Imager. Die Variante Lite (ohne Desktop) genügt vollkommen und läuft flotter.

Aktiviere im Imager unter den erweiterten Einstellungen (Zahnradsymbol):

  • SSH einschalten
  • Benutzername und Passwort setzen
  • WLAN-Zugangsdaten eintragen
  • Zeitzone korrekt setzen, zum Beispiel Europe/Zurich

Die Zeitzone ist wichtiger, als sie aussieht: Ein Kalender, der die falsche Uhrzeit hat, hebt den falschen Termin hervor.

Nach dem ersten Start verbindest du dich per SSH. Unter Windows geht das mit PuTTY, unter macOS und Linux direkt im Terminal:

Terminal
ssh benutzername@ip-adresse-des-pi

Dann bringst du das System auf den aktuellen Stand und installierst die benötigten Pakete:

Terminal
sudo apt update
sudo apt full-upgrade -y
sudo apt install -y git python3-pip python3-venv python3-pil \
                    python3-numpy python3-spidev python3-gpiozero \
                    fonts-dejavu-core

Der erste Befehl aktualisiert die Liste verfügbarer Programme, der zweite bringt das System auf den neuesten Stand. Der dritte installiert die Bausteine, die wir brauchen: git zum Herunterladen des Displaytreibers, python3-pil zum Zeichnen von Bildern, python3-spidev und python3-gpiozero für die Ansteuerung der Displaykontakte, und fonts-dejavu-core liefert die Schrift.

Zum Schluss neu starten:

Terminal
sudo reboot

04 SPI einschalten

SPI ist die Datenleitung, über die der Pi mit dem Display spricht. Ab Werk ist sie abgeschaltet.

Terminal
sudo raspi-config

Wähle Interface Options, dann SPI, dann Yes. Danach Finish und neu starten lassen.

Prüfe anschliessend, ob es geklappt hat:

Terminal
ls -l /dev/spidev*

Erscheinen zwei Einträge wie /dev/spidev0.0 und /dev/spidev0.1, ist alles in Ordnung. Kommt stattdessen No such file or directory, wurde SPI nicht aktiviert – dann noch einmal durch raspi-config.

05 Waveshare-Treiber holen

Der Hersteller stellt den Treiber öffentlich bereit. Wir laden ihn unverändert herunter und lassen ihn genau so, wie er ist:

Terminal
cd ~
git clone https://github.com/waveshareteam/e-Paper.git

Damit liegt der Treiber unter ~/e-Paper/RaspberryPi_JetsonNano/python/lib. Diesen Pfad brauchst du gleich in der Konfiguration.

Prüfen, ob die Datei für unser Modell dabei ist:

Terminal
ls ~/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in3f.py

Wird der Pfad ausgegeben, passt es. Erscheint eine Fehlermeldung, hast du vermutlich das falsche Displaymodell – siehe Kapitel 1.

Am Treiber wird nichts verändert. Das klingt selbstverständlich, ist aber bewusst so gebaut: Viele Anleitungen im Netz lassen dich Treiberdateien bearbeiten, und beim nächsten Update ist die Änderung weg. Unser Programm arbeitet stattdessen mit dem Treiber, wie er ist.

06 Zugang zu Google Kalender einrichten

Dieser Teil hat nichts mit dem Pi zu tun und passiert im Browser. Er ist der fummeligste Abschnitt der ganzen Anleitung – dafür danach nie wieder.

6.1 Projekt anlegen

Öffne die Google Cloud Console und melde dich mit dem Google-Konto an, dessen Kalender du anzeigen willst.

Erstelle oben links über die Projektauswahl ein neues Projekt. Der Name ist frei wählbar, zum Beispiel eink-kalender.

6.2 Kalender-Schnittstelle freischalten

Gehe zu APIs & Dienste → Bibliothek, suche nach Google Calendar API und klicke auf Aktivieren.

Damit erlaubst du deinem Projekt überhaupt erst, Kalenderdaten abzufragen.

6.3 Zustimmungsbildschirm einrichten

Gehe zu APIs & Dienste → OAuth-Zustimmungsbildschirm.

  • Nutzertyp: Extern
  • App-Name, Support-E-Mail und Entwickler-E-Mail ausfüllen
  • Bei den Bereichen (Scopes) brauchst du nichts hinzuzufügen

Der wichtigste Klick der ganzen Anleitung: Setze den Veröffentlichungsstatus auf „In Produktion". Solange dort „Testing" steht, verfällt dein Zugang nach sieben Tagen, und der Kalender bleibt stehen. Das ist der mit Abstand häufigste Grund, warum solche Projekte nach einer Woche aufhören zu funktionieren.

Google zeigt dir später beim Anmelden den Hinweis „Google hat diese App nicht verifiziert". Bei einem privaten Projekt ist das normal und unbedenklich – du bist ja Entwickler und Nutzer in einer Person. Du klickst dann auf Erweitert → Weiter zu … (unsicher).

6.4 Zugangsdaten erzeugen

Gehe zu APIs & Dienste → Anmeldedaten → Anmeldedaten erstellen → OAuth-Client-ID.

  • Anwendungstyp: Desktop-App
  • Name: frei wählbar

Lade die entstandene JSON-Datei herunter. Du brauchst sie gleich.

6.5 Kalender-IDs heraussuchen

Öffne Google Kalender. Fahre in der linken Spalte über einen Kalender, klicke auf die drei Punkte und wähle Einstellungen und Freigabe. Scrolle zu Kalender-ID und kopiere den Wert.

Für deinen Hauptkalender kannst du einfach das Wort primary verwenden.

Sammle die IDs aller Kalender, die auf dem Display erscheinen sollen.

07 Programmdateien anlegen

Lade das Projektarchiv herunter und entpacke es nach ~/eink-calendar. Danach sollte folgendes vorhanden sein:

Terminal
ls ~/eink-calendar
Ausgabe
authorize.py     config.example.toml  epaper.py    README.md
calendar_data.py eink_calendar.py     preview.py   renderer.py
requirements.txt systemd

Kurz, was die einzelnen Dateien tun:

Datei Aufgabe
eink_calendar.py Der Ablauf: Termine holen, Bild zeichnen, anzeigen
calendar_data.py Spricht mit Google und bereitet die Termine auf
renderer.py Zeichnet das Bild. Braucht keine Hardware
epaper.py Schaltet das Display sicher ein und wieder aus
authorize.py Einmalige Google-Anmeldung
preview.py Erzeugt ein Vorschaubild, ohne das Display zu belasten

Diese Aufteilung ist kein Selbstzweck: Weil renderer.py nichts von Hardware weiss, kannst du das Aussehen ändern und in zwei Sekunden per Vorschau prüfen, statt jedes Mal 35 Sekunden auf einen Bildwechsel zu warten.

Jetzt die Python-Umgebung einrichten:

Terminal
cd ~/eink-calendar
python3 -m venv --system-site-packages .venv
.venv/bin/pip install google-api-python-client google-auth google-auth-oauthlib

Der erste Befehl legt eine abgeschottete Python-Umgebung an. Das klingt umständlich, verhindert aber, dass sich dieses Projekt und das Betriebssystem gegenseitig die Bibliotheken durcheinanderbringen. Die Option --system-site-packages sorgt dafür, dass die eben per apt installierten Pakete trotzdem sichtbar bleiben – du lädst sie also nicht doppelt herunter.

Der zweite Befehl holt die drei Google-Bibliotheken dazu.

Zum Prüfen:

Terminal
.venv/bin/python -c "import googleapiclient, PIL, spidev, gpiozero; print('Alles da')"

08 Konfiguration ausfüllen

Alle persönlichen Angaben stehen in einer einzigen Datei. Im Programmcode selbst steht nichts davon: Die persönlichen Zugangsdaten liegen ausserhalb des veröffentlichten Projekts.

Zuerst die Zugangsdaten aus Kapitel 6.4 ablegen. Kopiere die heruntergeladene JSON-Datei mit einem Programm wie WinSCP oder per scp nach ~/eink-calendar/credentials.json:

Terminal
mv ~/client_secret_*.json ~/eink-calendar/credentials.json
chmod 600 ~/eink-calendar/credentials.json

Der zweite Befehl setzt die Zugriffsrechte so, dass nur du die Datei lesen kannst.

Jetzt die Konfigurationsdatei aus der Vorlage erzeugen und bearbeiten:

Terminal
cd ~/eink-calendar
cp config.example.toml config.toml
nano config.toml

Ersetze alle Stellen, die mit >>> markiert sind. Mindestens diese drei:

config.toml
[kalender]
ids = [
    "primary",
    "[email protected]",
]

[pfade]
waveshare_lib = "/home/DEIN_BENUTZER/e-Paper/RaspberryPi_JetsonNano/python/lib"

[allgemein]
zeitzone = "Europe/Zurich"

Speichern mit Strg+O, Enter, schliessen mit Strg+X.

Farben vergibst du im Abschnitt [farben]. Jeder Kalender, dem du dort ausdrücklich eine Farbe zuweist, bekommt diese; alle übrigen erhalten die Standardfarbe:

config.toml
[farben]
standard = "orange"
highlight = "gruen"

[farben.zuordnung]
"primary" = "blau"
"[email protected]" = "gelb"

Möglich sind ausschliesslich schwarz, weiss, gruen, blau, rot, gelb und orange – mehr kann das Panel nicht darstellen.

09 Einmalige Anmeldung

Jetzt verbindest du das Programm einmalig mit deinem Google-Konto.

Wenn du per SSH arbeitest, brauchst du dafür einen durchgereichten Port. Der Grund: Google schickt dich nach der Anmeldung an die Adresse http://localhost:8080 zurück. „localhost" ist aber immer der Rechner, auf dem der Browser läuft – also dein Laptop, nicht der Pi. Ohne Weiterleitung landet die Antwort im Nichts.

Trenne die SSH-Verbindung und verbinde dich neu:

Terminal
ssh -L 8080:localhost:8080 benutzername@ip-adresse-des-pi

In PuTTY stellst du das unter Connection → SSH → Tunnels ein: bei Source port 8080, bei Destination localhost:8080, dann Add und verbinden.

Dann auf dem Pi:

Terminal
cd ~/eink-calendar
.venv/bin/python authorize.py

Es erscheint eine lange Internetadresse. Kopiere sie in den Browser deines Laptops, melde dich an, klicke bei der Warnung auf Erweitert → Weiter zu … und erteile die Berechtigung. Im Terminal sollte danach stehen, wo das Token gespeichert wurde.

10 Vorschau ohne Display

Bevor zum ersten Mal auf das Panel geschrieben wird, prüfen wir alles andere. Dieser Schritt kostet zwei Sekunden statt 35 und belastet das Display gar nicht:

Terminal
.venv/bin/python preview.py --ausgabe vorschau.png

Das Programm meldet, wie viele Termine es gefunden hat und welcher hervorgehoben ist. Lade vorschau.png auf deinen Rechner und schau sie dir an.

Willst du sehen, wie eine volle Woche aussieht, ohne eigene Termine zu haben:

Terminal
.venv/bin/python preview.py --demo --ausgabe demo.png

Und so prüfst du, wie das Bild zu einer bestimmten Uhrzeit aussähe – praktisch, um die Hervorhebung zu testen:

Terminal
.venv/bin/python preview.py --zeit "2026-08-26 11:20" --ausgabe test.png

Stimmt die Vorschau, stimmt auch alles, was danach kommt. Sind die Farben falsch zugeordnet oder fehlen Termine, korrigierst du jetzt config.toml – ohne das Display auch nur einmal zu beschreiben.

11 Der erste echte Durchgang

Terminal
.venv/bin/python eink_calendar.py --erzwingen --ausfuehrlich

Jetzt dauert es rund 40 Sekunden. Das Display durchläuft mehrere Farbphasen und flackert dabei kräftig – so arbeiten Sieben-Farben-Panels, es ist kein Fehler.

--erzwingen bedeutet: schreibe auf jeden Fall, auch wenn sich nichts geändert hat. --ausfuehrlich zeigt jeden Schritt an. Im Normalbetrieb brauchst du beides nicht.

12 Automatikbetrieb

Damit der Kalender von selbst aktuell bleibt, übernimmt systemd die Steuerung – das ist die Verwaltung, die unter Linux alle Hintergrunddienste startet.

Zwei Dateien liegen im Ordner systemd. In beiden musst du deinen Benutzernamen einsetzen:

Terminal
cd ~/eink-calendar/systemd
sed -i "s/DEIN_BENUTZER/$USER/g" eink-calendar.service
grep -E "User|ExecStart|WorkingDirectory" eink-calendar.service

Der sed-Befehl ersetzt den Platzhalter durch deinen tatsächlichen Benutzernamen. Der grep-Befehl zeigt danach die drei betroffenen Zeilen, damit du kontrollieren kannst, dass es geklappt hat.

Installieren und einmal testweise auslösen:

Terminal
sudo cp eink-calendar.service eink-calendar.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl start eink-calendar.service
journalctl -u eink-calendar.service -n 20 --no-pager

Der letzte Befehl zeigt das Protokoll des Laufs. Sieht es gut aus, schaltest du den Automatikbetrieb ein:

Terminal
sudo systemctl enable --now eink-calendar.timer
systemctl list-timers --all | grep eink

In der Ausgabe muss ein konkreter Zeitpunkt in der Zukunft stehen. Zeigt die Spalte NEXT nur einen Bindestrich, warte eine Minute und wiederhole den Befehl.

Was in diesen beiden Dateien steht – und warum

Ein paar Zeilen darin sind das Ergebnis von Fehlern, die man sonst selbst macht:

systemd-Datei
After=time-sync.target
Wants=time-sync.target

Der Raspberry Pi hat keine batteriegepufferte Uhr. Nach dem Einschalten weiss er nicht, welcher Tag ist, bis er die Zeit aus dem Internet geholt hat. Ohne diese zwei Zeilen kann der Kalender starten, bevor die Uhr gestellt ist – und dann die falsche Woche zeichnen.

systemd-Datei
TimeoutStartSec=300

Bei Diensten vom Typ oneshot ist die Zeitüberwachung von systemd standardmässig abgeschaltet. Ohne diese Zeile würde ein hängengebliebener Aufruf ewig blockieren, ohne dass jemand eingreift. Fünf Minuten sind reichlich für einen Abruf plus 35 Sekunden Bildwechsel.

systemd-Datei
OnBootSec=45sec
OnUnitActiveSec=15min

45 Sekunden nach dem Einschalten läuft der erste Durchgang, danach alle 15 Minuten. Das Programm fragt jedes Mal den Kalender ab, schreibt das Display aber nur, wenn sich der Inhalt tatsächlich geändert hat. Die Hervorhebung bleibt dadurch minutengenau, ohne das Panel unnötig zu belasten.

13 Anpassen

Alle Anpassungen laufen über config.toml, gefolgt von einem Neustart des Timers ist nicht nötig – die Datei wird bei jedem Durchgang neu gelesen.

Andere Tage anzeigen. tage = 7 zeigt die ganze Woche statt nur Montag bis Freitag.

Anderes Zeitfenster. start_stunde und end_stunde bestimmen, welche Termine überhaupt erscheinen.

Ganztägige Termine. ganztags_anzeigen = false blendet Ferien und Geburtstage aus. Mit ganztags_nur_aus = ["kalender-id"] beschränkst du sie auf bestimmte Kalender.

Doppelte Termine. Wenn du mehrere Kalender abonniert hast, die sich überschneiden, erscheint derselbe Termin sonst mehrfach. duplikate_zusammenfassen = true fasst ihn zusammen. Welche Farbe gewinnt, entscheidet sich so: Vorrang hat ein Kalender, dem du in [farben.zuordnung] ausdrücklich eine Farbe zugewiesen hast; bei Gleichstand die Reihenfolge in [kalender] ids.

Startbild beim Einschalten

Beim Einschalten kann für einige Sekunden ein eigenes Bild erscheinen, bevor der Kalender kommt – zum Beispiel ein Logo.

Zuerst das Bild umwandeln. Das Panel kennt nur sieben Farben, deshalb muss ein Foto oder Logo vorher umgerechnet werden:

Terminal
cd ~/eink-calendar
.venv/bin/python konvertiere_startbild.py mein_logo.png startbild.png

Das Werkzeug passt das Bild auf 800 × 480 ein, verstärkt Sättigung und Kontrast und reduziert es auf die sieben darstellbaren Farben. Die Verstärkung ist kein Schönheitseffekt: Blasse Mitteltöne landen sonst alle im selben Ersatzton und das Bild wirkt matschig.

Dann in config.toml einschalten:

config.toml
[startbild]
aktiv = true
datei = "startbild.png"
anzeigedauer_sekunden = 150

Und den Dienst einrichten, der beim Einschalten läuft:

Terminal
cd ~/eink-calendar/systemd
sed -i "s/DEIN_BENUTZER/$USER/g" eink-calendar-start.service
sudo cp eink-calendar-start.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable eink-calendar-start.service

Zur Anzeigedauer: Waveshare empfiehlt mindestens 180 Sekunden zwischen zwei Bildwechseln. Der Schreibvorgang selbst dauert rund 35 Sekunden und zählt mit – 150 Sekunden Anzeigedauer ergeben also genau die empfohlenen 185 Sekunden. Kürzere Werte funktionieren, unterschreiten aber die Herstellerempfehlung; das Programm schreibt dann eine Warnung ins Protokoll. Rechne ausserdem damit, dass der Kalender erst nach Startbild plus Anzeigedauer plus einem weiteren Schreibvorgang erscheint.

Schrift im markierten Feld. highlight_schrift = "weiss" schreibt den hervorgehobenen Tag und Termin in Weiss. Das ist die Voreinstellung und auf dem Panel klar besser lesbar: Das ACeP-Grün wirkt dort deutlich dunkler und satter als auf einem Monitor. Mit "schwarz" erzwingst du schwarze Schrift, mit "auto" entscheidet die Helligkeit der gewählten Highlight-Farbe. Wenn du highlight auf eine helle Farbe wie Gelb änderst, gehört hier "schwarz" hin.

Schärfere Schrift. dithering = false lässt Text sauber schwarz erscheinen. Mit true werden Mischfarben in bunte Einzelpixel gestreut, was bei Fotos gut aussieht, bei Schrift aber unruhig wirkt.

Öfter oder seltener schreiben. nur_bei_aenderung = false schreibt bei jedem Durchgang. Das kostet Lebensdauer und bringt nichts – die Einstellung ist vor allem zum Testen gedacht.

14 Wenn etwas nicht funktioniert

Die erste Anlaufstelle ist immer das Protokoll:

Terminal
journalctl -u eink-calendar.service -n 50 --no-pager

„Kein Token unter …" Die einmalige Anmeldung aus Kapitel 9 fehlt oder ist fehlgeschlagen.

„Token konnte nicht erneuert werden" Fast immer steht der Veröffentlichungsstatus in der Google Cloud Console noch auf „Testing" – dann verfällt der Zugang nach sieben Tagen. Auf „In Produktion" umstellen und authorize.py einmal erneut ausführen.

„Waveshare-Treiber nicht gefunden" Der Pfad unter [pfade] waveshare_lib stimmt nicht. Kontrolliere ihn mit:

Terminal
ls ~/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in3f.py

Das Display bleibt weiss oder zeigt Streifen Prüfe, ob SPI aktiv ist (Kapitel 4) und ob der HAT fest sitzt. Bei sehr kaltem Raum kann auch die Temperatur die Ursache sein – unter 15 Grad arbeitet das Panel nicht zuverlässig.

Das Bild bleibt stehen und aktualisiert nicht mehr Prüfe, ob der Timer noch läuft:

Terminal
systemctl list-timers --all | grep eink

Falsche Woche oder falscher Termin hervorgehoben Kontrolliere die Systemzeit:

Terminal
timedatectl

Stimmt die Zeitzone nicht, korrigierst du sie mit:

Terminal
sudo timedatectl set-timezone Europe/Zurich

Zwei Programme schreiben gleichzeitig Wenn du eine ältere Version parallel laufen hast, kommen sich beide auf der SPI-Leitung in die Quere. Beachte: systemctl disable nimmt einen Timer nur aus dem Autostart, es stoppt ihn nicht. Dafür brauchst du:

Terminal
sudo systemctl stop alter-timer.timer

Sicherheit

Drei Dateien enthalten persönliche Daten und dürfen niemals in ein öffentliches Repository gelangen:

  • config.toml – deine Kalender-IDs
  • credentials.json – deine Zugangsdaten
  • token.json – dein Zugriffsschlüssel

Eine vierte Datei, state.json, ist ebenfalls ausgeschlossen. Sie enthält keine lesbaren persönlichen Daten, sondern nur eine Prüfsumme und einen Zeitstempel – sie gehört aber als reiner Maschinenzustand nicht ins Repository.

Die mitgelieferte .gitignore schliesst sie bereits aus. Wenn du diese Dateien trotzdem einmal weitergegeben hast, erneuere in der Google Cloud Console das Client-Secret und widerrufe das Token unter myaccount.google.com/permissions.

Quellen