def connect_wifi(known_nets): wl = WLAN() wl.mode(WLAN.STA) original_ssid = wl.ssid() original_auth = wl.auth() print(" [*] Scanning for known wifi nets") available_nets = wl.scan() print(' [+] Found {} WiFi APs.'.format(len(available_nets))) for available_net in available_nets: print(' - {} ({})'.format(available_net.ssid, available_net.rssi)) nets = frozenset([e.ssid for e in available_nets]) known_nets_names = frozenset([key for key in known_nets]) net_to_use = list(nets & known_nets_names) try: net_to_use = net_to_use[0] net_properties = known_nets[net_to_use] pwd = net_properties['pwd'] sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] if 'wlan_config' in net_properties: wl.ifconfig(config=net_properties['wlan_config']) wl.connect(net_to_use, (sec, pwd), timeout=10000) while not wl.isconnected(): machine.idle() # save power while waiting print(" [+] Connected to " + net_to_use + " with IP address: " + wl.ifconfig()[0]) except Exception as e: print( " [-] Failed to connect to any known network, going into AP mode") wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT)
import machine from keychain import WLAN_SSID, WLAN_PASSKEY from helpers import setup_rtc known_nets = [(WLAN_SSID, WLAN_PASSKEY)] if machine.reset_cause( ) != machine.SOFT_RESET: # needed to avoid losing connection after a soft reboot from network import WLAN wl = WLAN() # save the default ssid and auth original_ssid = wl.ssid() original_auth = wl.auth() wl.mode(WLAN.STA) available_nets = wl.scan() nets = frozenset([e.ssid for e in available_nets]) known_nets_names = frozenset([e[0] for e in known_nets]) net_to_use = list(nets & known_nets_names) try: net_to_use = net_to_use[0] pwd = dict(known_nets)[net_to_use] sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] wl.connect(net_to_use, (sec, pwd), timeout=10000) setup_rtc() except: wl.init(mode=WLAN.AP,
time.sleep(1) timeout -= 1 if wifi.isconnected(): print('Connected') else: print('Connection failed!') wifi = WLAN() print(wifi.mode() == WLAN.STA) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(mode=WLAN.AP) print(wifi.mode() == WLAN.AP) print(wifi.channel() == 1) print(wifi.auth() == None) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(0, mode=WLAN.AP, ssid='test-wlan', auth=(WLAN.WPA, '123456abc'), channel=7) print(wifi.mode() == WLAN.AP) print(wifi.channel() == 7) print(wifi.ssid() == 'test-wlan') print(wifi.auth() == (WLAN.WPA, '123456abc')) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(mode=WLAN.STA) print(wifi.mode() == WLAN.STA) scan_r = wifi.scan() print(len(scan_r) > 3) for net in scan_r: if net.ssid == testconfig.wlan_ssid: # test that the scan results contains the desired params
time.sleep(1) timeout -= 1 if wifi.isconnected(): print('Connected') else: print('Connection failed!') wifi = WLAN(0, WLAN.STA) print(wifi.mode() == WLAN.STA) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(mode=WLAN.AP) print(wifi.mode() == WLAN.AP) print(wifi.channel() == 1) print(wifi.auth() == None) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(0, mode=WLAN.AP, ssid='test-wlan', auth=(WLAN.WPA, '123456abc'), channel=7) print(wifi.mode() == WLAN.AP) print(wifi.channel() == 7) print(wifi.ssid() == 'test-wlan') print(wifi.auth() == (WLAN.WPA, '123456abc')) print(wifi.antenna() == WLAN.INT_ANT) wifi = WLAN(mode=WLAN.STA) print(wifi.mode() == WLAN.STA) time.sleep(5) # this ensures a full network scan
class WifiManager: def __init__(self, known_nets): self._known_nets = known_nets # create network in STAtion mode # pycom: device always starts up in AP-mode #self._wl = WLAN() #self._wl.mode(WLAN.STA) '''def print_debug(self, message): """print_debug() - for debugging """ if USE_DEBUG: print(msg) ''' # 2019-1203 new, due to Exception error in legacy WifiManager # pre-condition: self._known_nets is not None # post-condition: self._wl is created # returns: IP # URL: https://docs.pycom.io/tutorials/all/wlan/ def connect(self): """connect() - connects device according to network parameters in JSON-file.""" if machine.reset_cause() != machine.SOFT_RESET: # from network import WLAN self._wl = WLAN() self._wl.mode(WLAN.STA) original_ssid = self._wl.ssid() original_auth = self._wl.auth() print_debug("Wifimanager - scanning for known wifi nets...") available_nets = self._wl.scan() nets = frozenset([e.ssid for e in available_nets]) known_nets_names = frozenset([key for key in self._known_nets]) net_to_use = list(nets & known_nets_names) print_debug("Wifimanager - SSID to use...{}".format(net_to_use)) try: net_to_use = net_to_use[0] print_debug("Wifimanager - net to use...{}".format(net_to_use)) net_properties = self._known_nets[net_to_use] pwd = net_properties['pwd'] sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] print_debug( "Wifimanager - net_properties...{}".format(net_properties)) if 'wlan_config' in net_properties: print_debug("Wifimanager - wlan_config...{}".format( net_properties['wlan_config'])) self._wl.ifconfig(config=net_properties['wlan_config']) self._wl.connect(net_to_use, (sec, pwd), timeout=10000) ip = self.wait_for_networking(1) self._ssid = net_to_use print_debug("Connected to " + net_to_use + " with IP address:" + ip) except Exception as e: print( "Failed to connect to any known network, going into AP mode" ) self._wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT) self._ssid = None else: print_debug("Already connected to " + net_to_use + " with IP address:" + self._wl.ifconfig()[0]) return self._wl.ifconfig()[0] def wait_for_networking(self, dt=1): """ wait unitil network is connected and returns IP""" station = self._wl # network.WLAN(mode=network.WLAN.STA) while not station.isconnected(): time.sleep(dt) machine.idle() ip = station.ifconfig()[0] return ip # wrapper for disconnecting network def disconnect(self): """disconnect() - de-activate network interface, but leaves Wifi radio on""" self._wl.disconnect( ) # pycom - disconnect from Wifi, but leave Wif radio on. print_debug('WifiManager::Wifi disconnected') # wrapper for disabling Wifi radio def deinit(self): """deinit() - disable Wifi radio""" self._wl.deint() # pycom print_debug('WifiManager::Wifi radio off') # wrapper for network scan def scan(self): """scan() - Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi) """ return self._wl.scan() def change_access(self, user=None, passwrd=None): """change_access - change password for telnet and ftp access""" if (user is None) or (passwrd is None): print('WifiManager:: username and password must be specified') return server = Server() # from network # disable the server server.deinit() # enable the server again with new credentials # for ftp and telnet, not USB server.init(login=(user, passwrd), timeout=600) print_debug('WifiManager::password {} is changed...'.format(user)) # wrappers for wlan settings. @property def ssid(self): """ ssid() - returns SSID of connected Wifi network""" return self._ssid @property def isconnected(self): """isconnected() - returns if connected to Wifi (True) or not (False)""" return self._wl.isconnected() @property def ip(self): """ip() - returns IP of device on connected Wifi network""" return self._wl.ifconfig()[0] @property def mac(self): """returns MAC-address of device""" mac = hexlify(self._wl.mac(), ':').decode() # pycom # return (mac) # lower case return mac.upper() # ================================================ # legacy methods # ================================================ import json def __readjson(self, jsonfile): """readjson(file) - returns the contents of file in JSON-format""" with open(jsonfile, 'r') as infile: config = json.load(infile) if USE_DEBUG: print('WifiManager::JSON settings: {}'.format(config)) return config
class WiFiManager: def __init__(self, manager, settings): self.manager = manager self.settings = settings # WIFI settings. self.stations = self.settings.get('networking.wifi.stations') self.station = None def start(self): """ https://docs.pycom.io/tutorials/all/wlan.html https://github.com/pycom/pydocs/blob/master/firmwareapi/pycom/network/wlan.md """ # Todo: Propagate more parameters here, e.g. for using an external antenna. self.station = WLAN() #if machine.reset_cause() == machine.SOFT_RESET: # print("WiFi STA: Network connection after SOFT_RESET.") # self.print_short_status() # # Inform about networking status. # self.print_address_status() # return True # Save the default ssid and auth for restoring AP mode later original_ssid = self.station.ssid() original_auth = self.station.auth() # Inform about networking status. self.print_address_status() # Setup network interface. self.station.init() # Check WiFi connectivity. if self.station.isconnected(): log.info( "WiFi STA: Network connection already established, will skip scanning and resume connectivity." ) self.print_short_status() # Give system some breath. time.sleep(0.25) # Inform about networking status. self.print_address_status() return True # Prepare information about known WiFi networks. networks_known = frozenset( [station['ssid'] for station in self.stations]) log.info("WiFi STA: Starting interface") self.station.mode(WLAN.STA) # Attempt to connect to known/configured networks. log.info("WiFi STA: Directly connecting to configured networks: %s", list(networks_known)) try: self.connect_stations(networks_known) except: log.warning('WiFi: Switching to AP mode not implemented yet') # Todo: Reenable WiFi AP mode in the context of an "initial configuration" mode. """ log.info('WiFi: Switching to AP mode') # WLAN.AP, original_ssid, original_auth, WLAN.INT_ANT # TOOD: Make default channel configurable self.station.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT) """ def power_off(self): """ Power off all radio peripherals. - https://forum.pycom.io/topic/563/disabling-wifi-on-lopy - https://github.com/Hiverize/FiPy/commit/b6b15677 """ # WiFi if self.station: try: log.info('Turning off WiFi') self.station.deinit() except: log.exception('Turning off WiFi failed') def connect_stations(self, network_names): # Prepare information about known WiFi networks. network_map = {station['ssid']: station for station in self.stations} for network_name in network_names: try: # All the configuration details for this network. # { # 'ssid': 'FooBar', # 'password': '******', # 'ifconfig': ('192.168.42.42', '255.255.255.0', '192.168.42.1', '192.168.42.1'), # } network_selected = network_map[network_name] if self.connect_station(network_selected): break except Exception: log.exception( 'WiFi STA: Connecting to "{}" failed'.format(network_name)) if not self.station.isconnected(): self.forget_network(network_name) message = 'WiFi STA: Connecting to any network candidate failed' description = 'Please check your WiFi configuration for one of the ' \ 'station candidates {}.'.format(len(network_names)) log.error('{}. {}'.format(message, description)) log.warning( 'Todo: We might want to switch to AP mode here or alternatively ' 'buffer telemetry data to flash to be scheduled for transmission later.' ) raise WiFiException(message) def connect_station(self, network): network_name = network['ssid'] log.info('WiFi STA: Prepare connecting to network "{}"'.format( network_name)) auth_mode = self.get_auth_mode(network_name) log.info( 'WiFi STA: Attempt connecting to network "{}" with auth mode "{}"'. format(network_name, auth_mode)) password = network['password'] # TODO: Optionally, configure hostname. # https://docs.micropython.org/en/latest/library/network.WLAN.html # https://github.com/pycom/pycom-micropython-sigfox/pull/165 # https://forum.pycom.io/topic/3326/new-firmware-release-v1-18-0 if 'dhcp_hostname' in network: if hasattr(self.station, 'config'): log.ingo('WiFi STA: Using dhcp_hostname "{}"'.format( network['dhcp_hostname'])) self.station.config(dhcp_hostname=network['dhcp_hostname']) else: log.error('Could not set hostname on older MicroPython') # Optionally, configure static IP address. if 'ifconfig' in network: log.info( 'WiFi STA: Using static network configuration "{}"'.format( network_name)) self.station.ifconfig(config=network['ifconfig']) # Obtain timeout value. network_timeout = network.get('timeout', 15.0) # Set interval how often to poll for WiFi connectivity. network_poll_interval = 800 # Connect to WiFi station. log.info( 'WiFi STA: Starting connection to "{}" with timeout of {} seconds'. format(network_name, network_timeout)) self.station.connect(network_name, (auth_mode, password), timeout=int(network_timeout * 1000)) # Wait for station network to arrive. # ``isconnected()`` returns True when connected to a WiFi access point *and* having a valid IP address. retries = int(network_timeout * network_poll_interval) while not self.station.isconnected() and retries > 0: log.info( 'WiFi STA: Waiting for network "{}".'.format(network_name)) retries -= 1 # Save power while waiting. machine.idle() # Feed watchdog. self.manager.device.feed_watchdog() # Don't busy-wait. time.sleep_ms(network_poll_interval) if not self.station.isconnected(): raise WiFiException( 'WiFi STA: Unable to connect to "{}"'.format(network_name)) # Inform about networking status. self.print_short_status() self.print_address_status() return True def scan_stations(self): self.manager.device.feed_watchdog() # Inquire visible networks. log.info("WiFi STA: Scanning for networks") stations_available = self.station.scan() networks_found = frozenset([e.ssid for e in stations_available]) # Print names/SSIDs of networks found. log.info("WiFi STA: Networks available: %s", list(networks_found)) return stations_available # Compute set of effective networks by intersecting known with found ones. #network_candidates = list(networks_found & networks_known) #log.info("WiFi STA: Network candidates: %s", network_candidates) def get_ssid(self): return self.station.ssid() def get_ip_address(self): try: return self.station.ifconfig()[0] except: pass def get_auth_mode(self, network_name): # NVRAM key for storing auth mode per network. Maximum of 15 characters. auth_mode_nvs_key = self.auth_mode_nvs_key(network_name) # Get WiFi STA auth mode from NVRAM. try: import pycom auth_mode = pycom.nvs_get(auth_mode_nvs_key) log.info('WiFi STA: Auth mode from NVRAM with key=%s, value=%s', auth_mode_nvs_key, auth_mode) except: auth_mode = None # Fall back to find out WiFi STA auth mode by network scan. if auth_mode is None: log.info( 'WiFi STA: Unknown auth mode for network "%s", invoking WiFi scan', network_name) wifi_neighbourhood = self.scan_stations() #log.info('WiFi STA: Neighbourhood is %s', wifi_neighbourhood) for e in wifi_neighbourhood: if e.ssid == network_name: auth_mode = e.sec break if not auth_mode: message = 'WiFi STA: Unable to inquire auth mode for network "{}"'.format( network_name) log.warning(message) raise WiFiException(message) log.info( 'WiFi STA: Storing auth mode into NVRAM with key=%s, value=%s', auth_mode_nvs_key, auth_mode) try: import pycom pycom.nvs_set(auth_mode_nvs_key, auth_mode) except: log.exception('WiFi STA: Storing auth mode into NVRAM failed') return auth_mode def auth_mode_nvs_key(self, ssid): """ Hack to get a short representation of a WiFi SSID in order to squeeze it into a NVRAM key with a maximum length of 15 characters. Fixme: Review this. """ import hashlib import ubinascii digest = ubinascii.hexlify(hashlib.sha512(ssid).digest()).decode() identifier = 'wa.{}'.format(digest[15:27]) return identifier def forget_network(self, network_name): log.info('WiFi STA: Forgetting NVRAM data for network "{}"'.format( network_name)) auth_mode_nvs_key = self.auth_mode_nvs_key(network_name) try: import pycom pycom.nvs_erase(auth_mode_nvs_key) except: pass def print_short_status(self): log.info('WiFi STA: Connected to "{}" with IP address "{}"'.format( self.get_ssid(), self.get_ip_address())) def print_address_status(self): mac_address = self.humanize_mac_addresses(self.station.mac()) ifconfig = self.station.ifconfig() log.info('WiFi STA: Networking address (MAC): %s', mac_address) log.info('WiFi STA: Networking address (IP): %s', ifconfig) def humanize_mac_addresses(self, mac): info = {} if hasattr(mac, 'sta_mac'): info['sta_mac'] = format_mac_address( binascii.hexlify(mac.sta_mac).decode()) if hasattr(mac, 'ap_mac'): info['ap_mac'] = format_mac_address( binascii.hexlify(mac.ap_mac).decode()) return info def print_metrics(self): metrics = SystemWiFiMetrics(self.station).read() log.info('WiFi STA: Metrics: %s', metrics)
signal.signal(signal.SIGINT, sigint_handler) signal.signal(signal.SIGTERM, sigint_handler) # Initialize led matrix framebuffer on top of HAL display = LedMatrix(driver, config['LedMatrix']) driver.clear_display() if pycom_board: # We're running under MCU here from bootscene import BootScene scene = BootScene(display, config['Boot']) wlan = WLAN(mode=WLAN.STA) if not wlan.isconnected(): print('WLAN: Scanning for networks') scene.render(0, 0, 0) default_ssid, default_auth = wlan.ssid(), wlan.auth() candidates = wlan.scan() for conf in config['networks']: nets = [ candidate for candidate in candidates if candidate.ssid == conf['ssid'] ] if not nets: continue print('WLAN: Connecting to known network: {}'.format( nets[0].ssid)) wlan.connect(nets[0].ssid, auth=(nets[0].sec, conf['password'])) for i in range(1, 40): scene.render(i, 0, 0) time.sleep(0.2)
known_nets = { 'wifilocal': { 'pwd': 'PWD', 'wlan_config': ('192.168.x.x', '255.255.x.x', '192.168.x.x', '1.1.1.1') }, 'hotspot': { 'pwd': 'PWD' } } if machine.reset_cause() != machine.SOFT_RESET: from network import WLAN wlan = WLAN() wlan.mode(WLAN.STA) original_ssid = wlan.ssid() original_auth = wlan.auth() print("Scanning for known wifi nets") available_nets = wlan.scan() nets = frozenset([e.ssid for e in available_nets]) known_nets_names = frozenset([key for key in known_nets]) net_to_use = list(nets & known_nets_names) try: net_to_use = net_to_use[0] net_properties = known_nets[net_to_use] pwd = net_properties['pwd'] sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] if 'wlan_config' in net_properties: wlan.ifconfig(config=net_properties['wlan_config']) wlan.connect(net_to_use, (sec, pwd), timeout=10000)