"""Handles connecting to a wifi access point based on a valid wifi.json file""" ___license___ = "MIT" ___dependencies___ = ["dialogs", "sleep"] import network, os, json, dialogs, sleep, time _nic = None def nic(): global _nic if not _nic: _nic = network.WLAN() _nic.active(True) return _nic def connection_details(): data = None try: if "wifi.json" in os.listdir(): with open("wifi.json") as f: data = json.loads(f.read()) if 'ssid' not in data or not data['ssid']: data = None except ValueError as e: print(e) return data def ssid(): return connection_details()["ssid"] def connect(wait=True, timeout=10, show_wait_message=False, prompt_on_fail=True, dialog_title='TiLDA'): while True: if nic().isconnected(): return details = connection_details() if not details: if prompt_on_fail: choose_wifi(dialog_title=dialog_title) else: raise OSError("No valid wifi configuration") if not wait: connect_wifi(details, timeout=None, wait=False) return else: try: if show_wait_message: with dialogs.WaitingMessage(text="Connecting to '%s'...\n(%ss timeout)" % (details['ssid'], timeout), title=dialog_title): connect_wifi(details, timeout=timeout, wait=True) else: connect_wifi(details, timeout=timeout, wait=True) except OSError: if prompt_on_fail: retry_connect = dialogs.prompt_boolean( text="Failed to connect to '%s'" % details['ssid'], title=dialog_title, true_text="Try again", false_text="Change it", ) if not retry_connect: os.remove('wifi.json') os.sync() else: raise def connect_wifi(details, timeout, wait=False): if 'user' in details: nic().connect(details['ssid'], details['pw'], enterprise=True, entuser=details['user'], entmethod=nic().EAP_METHOD_PEAP0_MSCHAPv2, entserverauth=False) elif 'pw' in details: nic().connect(details['ssid'], details['pw']) else: nic().connect(details['ssid']) if wait: wait_until = time.ticks_ms() + timeout * 1000 while not nic().isconnected(): #nic().update() # todo: do we need this? if (time.ticks_ms() > wait_until): raise OSError("Timeout while trying to connect to wifi") sleep.sleep_ms(100) def is_connected(): return nic().isconnected() # returns wifi strength in %, None if unavailable def get_strength(): n = nic() if n.isconnected(): v = n.status("rssi"); if v: # linear range: -60 =100%; -100= 20% # todo: it's probably not linear, improve me. return v * 2 + 220 return None def get_security_level(ap): #todo: fix this n = nic() levels = { n.SCAN_SEC_OPEN: 0, # I am awful n.SCAN_SEC_WEP: 'WEP', n.SCAN_SEC_WPA: 'WPA', n.SCAN_SEC_WPA2: 'WPA2', } return levels.get(ap.get('security', None), None) def choose_wifi(dialog_title='TiLDA'): filtered_aps = [] with dialogs.WaitingMessage(text='Scanning for networks...', title=dialog_title): visible_aps = None while not visible_aps: visible_aps = nic().scan() print(visible_aps) sleep.sleep_ms(300) #todo: timeout visible_aps.sort(key=lambda x:x[3], reverse=True) # We'll get one result for each AP, so filter dupes for ap in visible_aps: title = ap[0] security = "?" # todo: re-add get_security_level(ap) if security: title = title + ' (%s)' % security ap = { 'title': title, 'ssid': ap[0], 'security': ap[4], } if ap['ssid'] not in [ a['ssid'] for a in filtered_aps ]: filtered_aps.append(ap) del visible_aps ap = dialogs.prompt_option( filtered_aps, text='Choose wifi network', title=dialog_title ) if ap: key = None if ap['security'] != 0: # Backward compat if ap['security'] == None: ap['security'] = 'wifi' key = dialogs.prompt_text("Enter %s key" % ap['security']) with open("wifi.json", "wt") as file: if key: conn_details = {"ssid": ap['ssid'], "pw": key} else: conn_details = {"ssid": ap['ssid']} file.write(json.dumps(conn_details)) os.sync() # todo: last time we had to hard reset here, is that still the case?