Raspberry Pi Pico W: WLAN-Uhr mit Zeitumstellung und Zeitzone

Dank integrierter Echtzeituhr (Real-time Clock, RTC) kann der Raspberry Pi Pico auch das aktuelle Datum und die Uhrzeit ausgeben. Vorausgesetzt, die Echtzeituhr wird beim Start mit der aktuellen Zeit korrekt eingestellt.
Normalerweise braucht eine Echtzeituhr eine Stromversorgung, damit die Zeit (in Sekunden) mitgeführt wird. Wird die Stromversorgung unterbrochen, beginnt die Echtzeituhr wieder bei Null zu zählen an und muss erneut eingestellt werden.

Mit dem Raspberry Pi Pico W (mit WLAN-Chip) besteht die Möglichkeit, bei einer aktiven WLAN-Verbindung die aktuelle Zeit von einem Zeitserver per NTP abzufragen und danach die integrierte Echtzeituhr einzustellen.

Aufbau und Bauteile

Raspberry Pi Pico W: WLAN-Stoppuhr mit Anzeige (TM1637)

Raspberry Pi Pico TM1637
Pin 38 GND GND
Pin 36 VCC +3,3V VCC
Pin 27 GPIO 21 CLK
Pin 26 GPIO 20 DIO

Schnell und einfach alle Bauteile zusammen bestellen

MicroPython-Bibliothek für TM1637

Zur Ansteuerung der 7-Segment-Anzeige TM1637 ist eine externe Bibliothek erforderlich, die heruntergeladen und mit dem Dateinamen „tm1637.py“ auf dem Raspberry Pi Pico gespeichert werden muss.

Probleme

Beim Einstellen der Echtzeituhr ergeben sich jedoch mehrere Probleme, die gelöst werden müssen, damit ein Raspberry Pi Pico immer die richtige Uhrzeit ausgeben kann.

  1. Problem: Zeitzone, die abhängig vom Standort ist.
  2. Problem: Zeitumstellung, die abhängig von der Region oder Land ist.

1. Problem: Zeitzone

Zeitzonen teilen die Welt in regionale Zeitabschnitte ein, um eine tageslichtabhängige Zeitmessung zu ermöglichen. Jede Zone repräsentiert einen Längengrad und hat eine standardisierte Zeit, basierend auf der Erdrotation.

In einem typischen Betriebssystem, das auf einem herkömmlichen Computer läuft, wird bei der Installation die Zeitzone einmalig eingestellt, in dem der Nutzer angibt wo er sich befindet. In einem MicroPython-Programmcode ist das nicht automatisch vorgesehen. Hier muss sich der Programmierer selber darum kümmern und zum Beispiel überlegen, welche Referenzzeit er verwendet. Als Referenzzeit wird typischerweise UTC verwendet.
UTC ist die Abkürzung für „coordinated universal time“, was die 1972 eingeführte koordinierte Weltzeit ist. Die so angegebene Zeit kann als Referenzzeit verwendet werden, die aber nur in der entsprechenden Zeitzone als lokale Zeit gilt. Damit die korrekte Zeit in Deutschland, Österreich und die Schweiz von der UTC abgeleitet werden kann, muss eine Stunde addiert werden, wodurch man die Mitteleuropäische Zeit (MEZ) erhält. Für die im Sommer geltende Mitteleuropäische Sommerzeit (MESZ) ist zusätzlich noch eine weitere Stunde zu addieren. Und damit wären wir schon beim nächsten Problem.

2. Problem: Zeitumstellung

Die Zeitumstellung ist der Wechsel von der Normalzeit (Winterzeit) auf die Sommerzeit und umgekehrt. Dabei werden die Uhren im Frühjahr eine Stunde vorgestellt und im Herbst eine Stunde zurückgestellt. Das soll die Tageslichtnutzung für Aktivitäten maximieren und die Energieeinsparung fördern.
In Deutschland findet die Zeitumstellung zweimal im Jahr statt. Die Uhren werden im Frühjahr, in der Regel am letzten Sonntag im März, um 2:00 Uhr morgens eine Stunde vor (auf 3:00) gestellt. Im Herbst erfolgt die Umstellung am letzten Sonntag im Oktober, um 3:00 Uhr morgens, indem die Uhren eine Stunde zurückgestellt (auf 2:00) werden.
Auch diese Umstellung erfolgt nicht automatisch, weshalb sich auch hier der Programmierung um eine Lösung kümmern muss

Lösung für Zeitzone und Zeitumstellung

Die Zeitzone zu berücksichtigen ist vergleichsweise einfach. Man muss nur eine Stunde zur UTC hinzuaddieren oder man stellt die Echtzeituhr gleich auf die MEZ ein. Die Frage ist aber, was macht man, wenn die Zeit im Frühjahr und Herbst umgestellt werden muss?
Der Begriff Zeitumstellung suggeriert, dass man die Zeit in der Echtzeituhr zum richtigen Zeitpunkt ändert. Denkbar wäre, dass man das automatisiert. Aber, dazu muss man auf die richtige Zeit prüfen. Damit man den Umstellzeitpunkt nicht verpasst, muss man das dauernd oder zumindest regelmässig tun. Das könnte man mit einem Timer lösen, was viel Rechenleistung kostet, wenn man bedenkt, dass die Zeit nur exakt 2 mal im Jahr umgestellt werden muss. Das ist natürlich nur begrenzt sinnvoll.

In der folgenden Lösung geht es darum, wie man die Zeitzone berücksichtigt und die Zeitumstellung mit MicroPython automatisieren kann. Beide Logiken sind hierzu in der Bibliothek „owntime“ externalisiert. Die Datei owntime.py muss im Verzeichnis „lib“ gespeichert werden.

# Bibliotheken laden
import machine
import time
import socket
import struct

# Sommerzeiten: 2021 bis 2037
dst_ranges =[(1616893200, 1635645600), (1648342800, 1667095200), (1679792400, 1698544800), 
             (1711846800, 1729994400), (1743296400, 1761444000), (1774746000, 1792893600), 
             (1806195600, 1824948000), (1837645200, 1856397600), (1869094800, 1887847200), 
             (1901149200, 1919296800), (1932598800, 1950746400), (1964048400, 1982800800), 
             (1995498000, 2014250400), (2026947600, 2045700000), (2058397200, 2077149600), 
             (2090451600, 2108599200), (2121901200, 2140048800)]
    
# Funktion: Zeit per NTP holen
def getTimeNTP():
    NTP_HOST = 'pool.ntp.org'
    EPOCH_YEAR = time.gmtime(0)[0]
    if EPOCH_YEAR == 2000:
        NTP_DELTA = 3155673600 # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
    elif EPOCH_YEAR == 1970:
        NTP_DELTA = 2208988800 # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60
    else:
        raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR))
    NTP_QUERY = bytearray(48)
    NTP_QUERY[0] = 0x1B
    addr = socket.getaddrinfo(NTP_HOST, 123)[0][-1]
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.settimeout(1)
        res = s.sendto(NTP_QUERY, addr)
        msg = s.recv(48)
        rt = time.gmtime(struct.unpack("!I", msg[40:44])[0] - NTP_DELTA)
    except:
        rt = (0,0,0,0,0,0,0)
    finally:
        s.close()
    return (rt[0], rt[1], rt[2], rt[6], rt[3], rt[4], rt[5], 0)

# Funktion: RTC-Zeit setzen
def setTime():
    # NTP-Zeit holen
    tm = getTimeNTP()
    # Zeit einstellen
    machine.RTC().datetime((tm[0], tm[1], tm[2], tm[3], tm[4], tm[5], tm[7], 0))
    print('Uhrzeit eingestellt: %02d:%02d' % (tm[4], tm[5]))
    print()

# Funktion: Lokale Zeit mit Zeitumstellung ausgeben
def localTime(TZ_OFFSET):
    dst_adjust = 0
    utc = time.time()
    # Prüfen ob Sommerzeit ist
    if any(lwr <= utc < upr for (lwr, upr) in dst_ranges): dst_adjust = 3600
    # Lokale Zeit ermitteln
    lt = time.gmtime(utc + ( TZ_OFFSET * 3600 ) + dst_adjust)
    return (lt[0], lt[1], lt[2], lt[6], lt[3], lt[4], lt[5], 0)

Zeitzone

Für die Zeitzone gibt es die Variable TZ_OFFSET, in der die Differenz zur UTC eingetragen werden muss. In Deutschland, Österreich und Schweiz ist das der Wert 1.

Zeit einstellen

Sofern per WLAN eine Verbindung zum Internet besteht, kann die integrierte Echtzeituhr automatisch eingestellt werden. Mit der Funktion **owntime.setTime()** wird einmalig die aktuelle Zeit per NTP ermittelt. Anschließend wird die integrierte Echtzeituhr mit der NTP-Zeit (UTC) eingestellt.

Datum und Uhrzeit anzeigen

Mit der Funktion owntime.localTime(TZ_OFFSET) wird die aktuelle Zeit der Echtzeituhr abgefragt, die Differenz der Zeitzone addiert und auch noch die Zeitumstellung berücksichtigt. Ausgegeben wird das, was wir normalerweise von rtc.datetime() erhalten würden. Nur eben mit der Berücksichtigung der eingestellten Zeitzone und der Zeitumstellung.

Programmcode

Der folgende Programmcode führt nach der Inbetriebnahme folgende Funktionen aus.

  1. Das Display wird initialisiert.
  2. Die Verbindung zum WLAN wird hergestellt.
  3. Datum und Uhrzeit werdenvon einem NTP-Zeitserver abgefragt und Echtzeituhr mit der UTC-Zeit eingestellt. Danach wird die WLAN-Verbindung beendet und deaktiviert, um Strom zu sparen. Die WLAN-Verbindung ist hier nur für das ermitteln der aktuellen UTC-Zeit erforderlich.
  4. Dann wird das Hauptprogramm als Endlos-Schleife gestartet. Hier geht es nur darum, die aktuelle Uhrzeit zu ermitteln und die Anzeige auf dem Display zu ändern.

Es müssen 2 Dinge eingestellt werden. Die Zugangsdaten für Dein WLAN (wlanSSID und wlanPW) und die Zeitzone, die schon auf die MEZ voreingestellt ist.

# Bibliotheken laden
import machine
import time
import network
import tm1637
import owntime

# WLAN-Konfiguration
wlanSSID = 'WLAN-Name'
wlanPW = 'WLAN-Passwort'
network.country('DE')

# Zeitzone
TZ_OFFSET = +1

# 1. Display initialisieren und Helligkeit einstellen (1 bis 7)
display = tm1637.TM1637(clk=machine.Pin(21), dio=machine.Pin(20))
display.brightness(3)

# 2. WLAN-Verbindung herstellen
wlan = network.WLAN(network.STA_IF)
if not wlan.isconnected():
    print('WLAN-Verbindung herstellen')
    wlan.active(True)
    wlan.connect(wlanSSID, wlanPW)
    for i in range(10):
        display.write([0, 0, 0, 0])
        if wlan.status() == 3:
            break
        print('.')
        time.sleep(0.5)
        display.numbers(0, 0)
        time.sleep(0.5)
    display.write([0, 0, 0, 0])

# 3. Zeit setzen
if wlan.isconnected():
    print('WLAN-Verbindung hergestellt')
    print()
    # Zeit setzen
    owntime.setTime()
    # WLAN-Verbindung beenden (optional)
    wlan.disconnect()
    #wlan.active(False)
    print('WLAN-Verbindung beendet und deaktiviert')
    print()
else:
    print('Keine WLAN-Verbindung / WLAN-Status:', wlan.status())

# 4. Hauptprogramm
while True:
    # Uhrzeit ändern
    datetime = owntime.localTime(TZ_OFFSET)
    # Ausgabe
    print('Aktuelle Uhrzeit: %02d:%02d' % (datetime[4], datetime[5]))
    display.numbers(datetime[4], datetime[5])
    time.sleep(60)
    #machine.lightsleep(60000)

Erweiterung

Denkbar wäre, die Änderung der Uhrzeit-Darstellung mit der Endlos-Schleife durch eine Timer-gesteuerte Lösung zu ersetzen. Dann könnte der Raspberry Pi Pico auch noch eine andere Aufgabe erledigen.

Der Vorteil der Endlos-Schleife ist, dass sich das „time.sleep“ Durch „machine.lightsleep“ ersetzen und dadurch Strom sparen lässt.

Weitere verwandte Themen:

Frag Elektronik-Kompendium.de

Hardware-nahes Programmieren mit dem Raspberry Pi Pico und MicroPython

Elektronik-Set Pico Edition

Das Elektronik-Set Pico Edition ist ein Bauteile-Sortiment mit Anleitung zum Experimentieren und Programmieren mit MicroPython.

  • LED: Einschalten, ausschalten, blinken und Helligkeit steuern
  • Taster: Entprellen und Zustände anzeigen
  • LED mit Taster einschalten und ausschalten
  • Ampel- und Lauflicht-Steuerung
  • Elektronischer Würfel
  • Eigene Steuerungen programmieren

Elektronik-Set jetzt bestellen Online-Workshop buchen

Online-Workshop: Programmieren mit dem Raspberry Pi Pico

Programmieren mit dem Raspberry Pi Pico

Gemeinsam mit anderen und unter Anleitung experimentieren? Wir bieten unterschiedliche Online-Workshops zum Raspberry Pi Pico und MicroPython an. Einführung in die Programmierung, Sensoren programmieren und kalibrieren, sowie Internet of Things und Smart Home über WLAN und MQTT.

Online-Workshop buchen

Besuchen Sie unser fast monatlich stattfindendes Online-Meeting PicoTalk und lernen Sie uns kennen. Die Teilnahme ist kostenfrei.

Termine und Newsletter-Anmeldung

 

Elektronik-Sets für das Hardware-nahe Programmieren