🍪 Privacy & Transparency

We and our partners use cookies to Store and/or access information on a device. We and our partners use data for Personalised ads and content, ad and content measurement, audience insights and product development. An example of data being processed may be a unique identifier stored in a cookie. Some of our partners may process your data as a part of their legitimate business interest without asking for consent. To view the purposes they believe they have legitimate interest for, or to object to this data processing use the vendor list link below. The consent submitted will only be used for data processing originating from this website. If you would like to change your settings or withdraw consent at any time, the link to do so is in our privacy policy accessible from our home page..

Vendor List | Privacy Policy
Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry PI

Menu
  • Projekte
    • LED’s
    • Servo & Schrittmotoren
    • Sound
    • LCD’s
    • Kommunikation
    • Sicherheit
    • Weekend Project
  • Arduino
    • Tutorials
    • ProMini
      • Anschließen & Programmieren
    • Nano
      • Arduino Nano – Übersicht
    • UNO
      • Übersicht
    • MEGA 2560
      • Übersicht
    • Leonardo
      • Übersicht
    • NodeMCU
      • NodeMCU – “Einer für (fast) Alles!”
    • Lilypad
      • Arduino: Lilypad “Jetzt Geht’s Rund!”
    • WEMOS
      • WEMOS D1 – Arduino UNO kompatibles Board mit ESP8266 Chip
      • WEMOS D1 Mini – Übersicht
      • Wemos D1 mini Shields
    • STM32x
      • STM32F103C8T6 – Übersicht
    • Maker UNO
      • Maker UNO – Überblick und Test
    • ATTiny85
      • Mini Arduino mit ATTiny85 Chip
      • ATtiny85 mit dem Arduino UNO beschreiben
  • Android
  • Über mich
  • DeutschDeutsch
  • EnglishEnglish
Menu

Raspberry Pi Pico W – Zeit aus dem Internet lesen und auf einem Display anzeigen

Posted on 27. Juli 20223. Mai 2023 by Stefan Draeger

Wie man die Zeit von Time Server aus dem Internet lädt und mit dem neuen Raspberry Pi Pico W auf einem LCD-Display per I²C anzeigen lassen kann, möchte ich dir in diesem ausführlichen Beitrag zeigen.

Den neuen Raspberry Pi Pico W mit WiFi Support habe ich dir bereits in folgenden Beiträgen vorgestellt und einige kleine Projekte gezeigt.

  • Raspberry Pi Pico W mit Wi-Fi Support
  • Raspberry Pi Pico W – Webserver programmieren
  • Raspberry Pi Pico W mit Infineon CYW43438 Chip
  • Raspberry Pi Pico W – anzeigen von Sensordaten auf einer Webseite
  • Raspberry Pi Pico W – Webseite ins Internet veröffentlichen

  • Benötigte Ressourcen für dieses Projekt
  • Aufbau der Schaltung, Raspberry Pi Pico W mit LCD-Display
  • Pinout des Raspberry Pi Pico (W)
    • Erweiterungsplatine für den Raspberry Pi Pico
  • I²C Adapter für LCD-Display
  • Programmieren des LCD-Displays in der Thonny IDE mit MicroPython
    • Download & kopieren des Modules für das LCD-Display
    • Troubleshooting
      • OSError 28
      • ValueError: bad SCL pin / bad SDA pin
    • Quellcode – „Hello World!“ auf dem LCD-Display
    • Auslesen einer Zeit vom Server
  • Fertiges Programm

Benötigte Ressourcen für dieses Projekt

Für dieses Projekt benötigst du, bzw. habe ich verwendet:

  • einen Raspberry Pi Pico W,
    • ein Micro-USB Datenkabel,
  • ein 2×16 Zeichen LCD-Display mit I²C Schnittstelle,
  • diverse Breadboardkabel

Aufbau der Schaltung, Raspberry Pi Pico W mit LCD-Display

In diesem Beitrag verwende ich ein einfaches 2×16 Zeichen LCD-Display mit I²C Schnittstelle. Es gibt jedoch auch größere Displays mit mehr Zeilen & Zeichen, wo du dann auch mehr Informationen anzeigen lassen kannst.

Raspberry Pi Pico mit LCD-Display via I²C
Raspberry Pi Pico mit LCD-Display via I²C

Der Raspberry Pi Pico W hat 2 I²C Schnittstellen, welche du über die nachfolgenden Pins erreichen kannst:

  • I²C 0
    • SDA – GP0, GP8, GP12, GP16, GP20
    • SCL – GP1, GP9, GP13, GP17, GP21
  • I²C 1
    • SDA – GP2, GP6, GP10, GP14, GP18, GP26
    • SCL – GP3, GP7, GP11, GP15, GP19, GP27
Auf der Schaltung - Raspberry Pi Pico W mit 2x20 Zeichen LCD-Display
Auf der Schaltung – Raspberry Pi Pico W mit 2×20 Zeichen LCD-Display

Pinout des Raspberry Pi Pico (W)

Der neue Raspberry Pi Pico W ist mit dem Vorgängermodell von den Pins identisch, d.h. du kannst deine bestehenden Projekte recht einfach um die WiFi Fähigkeit erweitern.

Pinout des Raspberry PI Pico
Pinout des Raspberry PI Pico

Erweiterungsplatine für den Raspberry Pi Pico

Für das Vorgängermodell dem Raspberry Pi Pico von 2021 habe ich ein kleines Board entwickelt welches mit die I²C Pins sowie ein paar GPIOs auf Groove Konnektoren bereitstellt.

Raspberry Pi Pico W auf DIY Expansionboard
Raspberry Pi Pico W auf DIY Expansionboard

I²C Adapter für LCD-Display

Das verwendete LCD-Display hat einen kleinen I²C Adapter auf der Rückseite verbaut. Dieser Adapter verfügt über die Pins SDA, SCL, VCC und GND sowie über einen Drehpotentiometer (blaues Bauteil im Bild) über welchen die Helligkeit der Schrift gesteuert werden kann.

I²C Adapter für das LCD-Display
I²C Adapter für das LCD-Display

Programmieren des LCD-Displays in der Thonny IDE mit MicroPython

Für die Programmierung nutze ich die Thonny IDE welche kostenfrei unter https://thonny.org/ für Microsoft Windows, macOS & auch Linux heruntergeladen werden kann.

Download & kopieren des Modules für das LCD-Display

Für die Programmierung des LCD-Displays verwende ich ein Modul, welches vom GitHub Repository dhylands/python_lcd geladen werden kann.

Von diesem Repository benötigen wir jedoch nur die beiden Dateien:

  • https://github.com/dhylands/python_lcd/blob/master/lcd/lcd_api.py
  • https://github.com/dhylands/python_lcd/blob/master/lcd/machine_i2c_lcd.py

Diese beiden Dateien müssen wir auf dem Pi Pico im Ordner „lib“ speichern. Da wir jedoch keinen direkten Zugriff auf diesem Ordner haben, müssen wir die beiden Dateien in einem Editor öffnen (zbsp. Notepad++). Im geöffneten Editor markieren und kopieren, wir den gesamten Text in einem geöffneten Tab in der Thonny IDE und speichern dieses in den Ordner „lib“ unter den jeweiligen Dateinamen.

Troubleshooting

Beim Programmieren sind mir einige Fehlermeldungen ausgegeben worden, welche ich dir hier gerne zeigen möchte.

OSError 28

Diesen Fehler erhältst du, wenn der Speicher des Mikrocontrollers aufgebraucht ist. D.h. du musst Speicher freigeben, um diesen Fehler zu beheben.

Dieses können zbsp. nicht benötigte Bibliotheken sein, welche auf dem Mikrocontroller abgelegt wurden.

ValueError: bad SCL pin / bad SDA pin

Die konfigurierte I²C Verbindung ist nicht lesbar. Hier musst du deine Verkabelung und die verwendete Adresse prüfen.

Quellcode – „Hello World!“ auf dem LCD-Display

Schreiben wir zunächst in jede Zeile des Displays ein paar Zeichen.

from time import sleep
from machine import I2C, Pin
from machine_i2c_lcd import I2cLcd

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000)
lcd = I2cLcd(i2c, 0x27, 2, 16)

zeile1  = 'Hello World!';
zeile2 = 'from Pi Pico W'

lcd.putstr(zeile1 + "\n" + zeile2)
sleep(2)
Auf der Schaltung - Raspberry Pi Pico W mit 2x20 Zeichen LCD-Display
Auf der Schaltung – Raspberry Pi Pico W mit 2×20 Zeichen LCD-Display

Auslesen einer Zeit vom Server

Als Dienst nutze ich den Server http://worldtimeapi.org welchen wir in der URL die Zeitzone übergeben wie zbsp. http://worldtimeapi.org/api/timezone/Europe/Berlin und als Antwort ein JSON mit den Daten erhalten.

Damit wir diesen HTTP Request absenden und einen Response vom Server empfangen können, müssen wir uns zu einem bestehenden WLAN Netzwerk verbunden haben. Wie du das machst, habe ich dir bereits im Beitrag Raspberry Pi Pico W – Webserver programmieren gezeigt.

Hier der Vollständigkeit der Code zum Herstellen einer Verbindung zu einem WLAN Netzwerk.

import network
import time
ssid = '*****'
password = '*******'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
print("Waiting to connect:")
while not wlan.isconnected() and wlan.status() >= 0:
    print(".", end="")   
    time.sleep(1)
print("")
print(wlan.ifconfig())

Wenn diese Verbindung aufgebaut ist, dann müssen wir einen Request an die oben genannte Adresse senden und den Response (ein JSON) auswerten.

Die Funktion zum Absenden des HTTP Requests und Empfangen des HTTP Response habe ich aus der offiziellen Dokumentation unter https://docs.micropython.org/en/latest/esp8266/tutorial/network_tcp.html entnommen.

# Funktion zum absenden eines HTTP Request und
# Rückgabe des HTTP Response
# Quelle: https://docs.micropython.org/en/latest/esp8266/tutorial/network_tcp.html
def http_get(url):
    result = ''
    _, _, host, path = url.split('/', 3)
    addr = socket.getaddrinfo(host, 80)[0][-1]
    s = socket.socket()
    s.connect(addr)
    s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
    while True:
        data = s.recv(100)
        if data:
            result = result + str(data, 'utf8')
        else:
            break
    s.close()
    return result

# Ermitteln des JSONs aus dem HTTP Response
def findJson(response):
    txt = 'abbreviation'
    return response[response.find(txt)-2:]

Aus diesem JSON Response können wir nun diverse Informationen entnehmen.

In meinem Fall interessiere ich mich für den UNIX Timestamp „unixtime“.

{
   "abbreviation":"CEST",
   "client_ip":"80.128.77.199",
   "datetime":"2022-07-25T14:22:21.415593+02:00",
   "day_of_week":1,
   "day_of_year":206,
   "dst":true,
   "dst_from":"2022-03-27T01:00:00+00:00",
   "dst_offset":3600,
   "dst_until":"2022-10-30T01:00:00+00:00",
   "raw_offset":3600,
   "timezone":"Europe/Berlin",
   "unixtime":1658751741,
   "utc_datetime":"2022-07-25T12:22:21.415593+00:00",
   "utc_offset":"+02:00",
   "week_number":30
}

Damit die Daten aus dem JSON (eigentlich ein einfacher String) ausgelesen werden kann, wandeln wir dieses in ein Dictionary um.

import json
aDict = json.loads(jsonData)

Nun können wir auf die Werte recht einfach mit dem entsprechenden Key zugreifen und den UNIX Timestamp in ein Tupel mit den Datum & Zeit Werten umwandeln.

# parsen des Zeitstempels
# Parameter ist das JSON als Dictionary
def parseDateTimeStr(responeDict):
    # umwandeln des UNIX Timestamp in eine Liste aus Datum & Zeit Werten
    dateTime = time.localtime(int(responeDict['unixtime']))
    year = dateTime[0]
    month = dateTime[1]
    dayOfMonth = dateTime[2]
    
    # Wenn der Monat kleiner als 10 ist,
    # dann eine führende Null anhängen
    if month < 10:
        month = str('0' + str(month))
        
    if dayOfMonth < 10:
        dayOfMonth = str('0' + str(dayOfMonth))

    dateStr = str(dayOfMonth)+'.'+str(month)+'.'+str(year)

    hour = dateTime[3]
    minutes = dateTime[4]

    # offset für die Uhrzeit auslesen
    timeOffset = responeDict['utc_offset']
    # Wenn der Offset mit einem Minus beginnt
    # dann soll der Wert abgezogen werden
    if timeOffset[0:1] == '-':
        hour = hour - int(timeOffset[1:3])
    elif timeOffset[0:1] == '+':
        # beginnt der Offset mit einem "+"
        # dann soll die Zeit addiert werden
        hour = hour + int(timeOffset[1:3])

    if hour < 10:
        hour = str('0' + str(hour))

    if minutes < 10:
        minutes = str('0' + str(minutes))
    
    timeStr = str(hour)+':'+str(minutes)
    # auslesen der Zeitzone
    timezone = responeDict['timezone']
    # zurückgeben der Zeitzone, des Datums sowie der Uhrzeit
    return timezone, dateStr, timeStr

Die ermittelten Werte für timezone, dateStr und timeStr speichern wir uns in einer Variable welche wir auf dem Display dann mit der Funktion „displayDateTime“ anzeigen lassen wollen.

In der Funktion wird die Zeichenkette für die Timezone in min. 16 Zeichen umgewandelt bzw. es werden entsprechende Leerzeichen ergänzt.

Der Hintergrund ist das wenn es weniger Zeichen sind, dann wird kein vernünftiger & zuverlässiger Zeilenumbruch gemacht. Das ist vor allem beim Aktualisieren des LCD-Displays aufgefallen.

# parsen des Zeitstempels aus dem Dictionary
timezone, dateStr, timeStr = parseDateTimeStr(aDict)
# ausgeben der Werte auf dem LCD-Display
displayDateTime(timezone, dateStr, timeStr)
# Anzeigen der Daten auf dem Display
# Hinweis: Wenn die Zeichen der Zeitzone
# länger als 16 Zeichen ist, dann wird
# diese automatisch umgebrochen!
def displayDateTime(timezone, dateStr, timeStr):
    timezone = "{:<16}".format(timezone)
    lcd.putstr(timezone +"\n" +dateStr + " " + timeStr)
    time.sleep(2)

Die Main Funktion mit den Aufrufen der einzelnen Funktionen und die Endlosschleife.

# Main Funktion
def main():
    # Aufbau der Wifi-Verbindung
    wifiConnect()
    # Auslesen des HTTP Response
    response = http_get(url)
    # ermitteln des JSONs
    jsonData = findJson(response)
    # umwandeln des JSONs in ein Dictionary
    aDict = json.loads(jsonData)
    # parsen des Zeitstempels aus dem Dictionary
    timezone, dateStr, timeStr = parseDateTimeStr(aDict)
    # ausgeben der Werte auf dem LCD-Display
    displayDateTime(timezone, dateStr, timeStr)

# Aufrufen der Funktion main()
while True:
    main()
    # eine Pause von 60 Sekunden einlegen
    # Der Server leht die Verbindung ab wenn der Intervall
    # des Zugriffs zu klein ist.
    time.sleep(60)

Fertiges Programm

Hier nun das fertige Programm zum einfachen Download:

Uhrzeit aus dem Internet auf LCD-Display anzeigenHerunterladen
import network
import socket
import time
import json
from machine import I2C, Pin
from machine_i2c_lcd import I2cLcd

#Zugangsdaten zum WLAN Netzwerk
ssid = 'FRITZBox7590GI_EXT'
password = '22894580214767401850'

#LCD-Display
lines = 2
cols = 16

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000)
lcd = I2cLcd(i2c, 0x27, lines, cols)

#Adresse welche uns das JSON mit den Zeitdaten liefert
service = 'http://worldtimeapi.org/api/timezone/'
url = service + 'Europe/Berlin'

# Aufbau einer WiFi Verbindung
def wifiConnect():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)

    print("Waiting to connect:")
    while not wlan.isconnected() and wlan.status() >= 0:
        print(".", end="")   
        time.sleep(1)
    print("")
    print(wlan.ifconfig())

# Funktion zum absenden eines HTTP Request und
# Rückgabe des HTTP Response
# Quelle: https://docs.micropython.org/en/latest/esp8266/tutorial/network_tcp.html
def http_get(url):
    result = ''
    _, _, host, path = url.split('/', 3)
    addr = socket.getaddrinfo(host, 80)[0][-1]
    s = socket.socket()
    s.connect(addr)
    s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
    while True:
        data = s.recv(100)
        if data:
            result = result + str(data, 'utf8')
        else:
            break
    s.close()
    return result

# Ermitteln des JSONs aus dem HTTP Response
def findJson(response):
    txt = 'abbreviation'
    return response[response.find(txt)-2:]

# parsen des Zeitstempels
# Parameter ist das JSON als Dictionary
def parseDateTimeStr(responeDict):
    # umwandeln des UNIX Timestamp in eine Liste aus Datum & Zeit Werten
    dateTime = time.localtime(int(responeDict['unixtime']))
    year = dateTime[0]
    month = dateTime[1]
    dayOfMonth = dateTime[2]
    
    # Wenn der Monat kleiner als 10 ist,
    # dann eine führende Null anhängen
    if month < 10:
        month = str('0' + str(month))
        
    if dayOfMonth < 10:
        dayOfMonth = str('0' + str(dayOfMonth))

    dateStr = str(dayOfMonth)+'.'+str(month)+'.'+str(year)

    hour = dateTime[3]
    minutes = dateTime[4]

    # offset für die Uhrzeit auslesen
    timeOffset = responeDict['utc_offset']
    # Wenn der Offset mit einem Minus beginnt
    # dann soll der Wert abgezogen werden
    if timeOffset[0:1] == '-':
        hour = hour - int(timeOffset[1:3])
    elif timeOffset[0:1] == '+':
        # beginnt der Offset mit einem "+"
        # dann soll die Zeit addiert werden
        hour = hour + int(timeOffset[1:3])

    if hour < 10:
        hour = str('0' + str(hour))

    if minutes < 10:
        minutes = str('0' + str(minutes))
    
    timeStr = str(hour)+':'+str(minutes)
    # auslesen der Zeitzone
    timezone = responeDict['timezone']
# zurückgeben der Zeitzone, des Datums sowie der Uhrzeit
    return timezone, dateStr, timeStr

# Anzeigen der Daten auf dem Display
# Hinweis: Wenn die Zeichen der Zeitzone
# länger als 16 Zeichen ist, dann wird
# diese automatisch umgebrochen!
def displayDateTime(timezone, dateStr, timeStr):
    timezone = "{:<16}".format(timezone)
    lcd.putstr(timezone +"\n" +dateStr + " " + timeStr)
    time.sleep(2)

# Main Funktion
def main():
    # Aufbau der Wifi-Verbindung
    wifiConnect()
    # Auslesen des HTTP Response
    response = http_get(url)
    # ermitteln des JSONs
    jsonData = findJson(response)
    # umwandeln des JSONs in ein Dictionary
    aDict = json.loads(jsonData)
    # parsen des Zeitstempels aus dem Dictionary
    timezone, dateStr, timeStr = parseDateTimeStr(aDict)
    # ausgeben der Werte auf dem LCD-Display
    displayDateTime(timezone, dateStr, timeStr)

# Aufrufen der Funktion main()
while True:
    main()
    # eine Pause von 60 Sekunden einlegen
    # Der Server leht die Verbindung ab wenn der Intervall
    # des Zugriffs zu klein ist.
    time.sleep(60)

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Kategorien

Tools

  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator
  • Widerstandsrechner
  • Rechner für Strom & Widerstände
  • ASCII Tabelle

Meta

  • Videothek
  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Kontakt
  • Cookie-Richtlinie (EU)

Links

Blogverzeichnis Bloggerei.de Blogverzeichnis TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com
©2023 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb