"""WLAN-Anbindung des XIAO ESP32-C3 (MicroPython). Die Zugangsdaten stehen in wifi_config.py, das nicht im Git liegt -- Vorlage ist wifi_config_example.py. Zeitverhalten kommt aus config.py. import wifi wifi.connect() # einmal verbinden, wirft WifiError bei Misserfolg wifi.ensure() # vor jeder Abfrage: verbunden halten WifiError erbt von displayloop.LinkError, damit die Poll-Schleife den Ausfall selbst abfaengt und "KEIN WLAN" anzeigt, statt abzustuerzen. """ import time import config import ticks from displayloop import LinkError try: # MicroPython import network except ImportError: # auf dem Mac nicht vorhanden network = None class WifiError(LinkError): """WLAN nicht verfuegbar oder Zugangsdaten fehlen.""" _wlan = None def credentials(): """(SSID, Passwort) aus wifi_config.py holen.""" try: import wifi_config except ImportError: raise WifiError("wifi_config.py fehlt -- wifi_config_example.py " "kopieren, ausfuellen und auf den ESP32 kopieren") try: return wifi_config.SSID, wifi_config.PASSWORD except AttributeError: raise WifiError("wifi_config.py braucht SSID und PASSWORD") def station(): """Das WLAN-Interface im Station-Modus, aktiviert.""" global _wlan if network is None: raise WifiError("network fehlt -- laeuft dieser Code auf dem ESP32?") if _wlan is None: _wlan = network.WLAN(network.STA_IF) if not _wlan.active(): _wlan.active(True) return _wlan def connected(): """True, wenn eine WLAN-Verbindung steht.""" if network is None or _wlan is None: return False return _wlan.isconnected() def connect(timeout=None, log=None): """Verbinden und warten, bis eine IP steht. Liefert die ifconfig-Tupel.""" if timeout is None: timeout = config.WIFI_TIMEOUT if log is None: log = print wlan = station() if wlan.isconnected(): return wlan.ifconfig() ssid, password = credentials() log("WLAN: verbinde mit %s ..." % ssid) wlan.connect(ssid, password) end = ticks.deadline(timeout) while not wlan.isconnected(): # Kurz schlafen statt hart zu pollen: der Verbindungsaufbau laeuft im # Hintergrund und braucht die Rechenzeit selbst. time.sleep(0.2) if ticks.expired(end): # Die Verbindung abbrechen, sonst versucht die Firmware im # Hintergrund weiter und der naechste connect() kollidiert damit. try: wlan.disconnect() except OSError: pass raise WifiError("keine Verbindung zu %s nach %g s" % (ssid, timeout)) cfg = wlan.ifconfig() log("WLAN: verbunden, IP %s" % cfg[0]) return cfg def ensure(timeout=None, log=None): """Sicherstellen, dass das WLAN steht -- fuer displayloop.ensure_link. Steht die Verbindung schon, kostet der Aufruf praktisch nichts. Sonst wird neu verbunden; scheitert das, fliegt WifiError (= LinkError) und die Poll-Schleife zeigt "KEIN WLAN" an und versucht es beim naechsten Durchlauf erneut. """ if connected(): return connect(timeout=timeout, log=log) def ifconfig(): """(IP, Netzmaske, Gateway, DNS) oder None, wenn nicht verbunden.""" return _wlan.ifconfig() if connected() else None def disconnect(): """Verbindung trennen und das Interface abschalten.""" global _wlan if _wlan is not None: try: _wlan.disconnect() _wlan.active(False) except OSError: pass _wlan = None