From 6dee7fff7e5dc2750fd05c4a2ff564e53dd73f72 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Tue, 6 Jan 2026 14:10:41 +0100 Subject: [PATCH] feat: Allow configuring WiFi security Allow choosing between the three security modes exposed by the micropython cyw43 wifi driver. Also allow setting up security in AP mode. Improve the WiFi section of the configuration UI. Signed-off-by: Matthias Blankertz --- software/frontend/index.html | 18 +++++++++++++++--- software/src/main.py | 20 +++++++++++++++----- software/src/utils/config.py | 7 +++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/software/frontend/index.html b/software/frontend/index.html index e05bc11..43de408 100644 --- a/software/frontend/index.html +++ b/software/frontend/index.html @@ -359,7 +359,10 @@ 'root.LED_COUNT': 'Length of WS2182 (Neopixel) LED chain', 'root.VOLUME_MAX': 'Maximum volume (0-255)', 'root.VOLUME_BOOT': 'Volume at startup (0-255)', - 'root.LED_MAX': 'Maximum LED brightness (0-255)' + 'root.LED_MAX': 'Maximum LED brightness (0-255)', + 'root.WIFI.SSID': 'Network name (SSID) (leave empty for AP mode)', + 'root.WIFI.PASSPHRASE': 'Password', + 'root.WIFI.SECURITY': 'Security mode' }; const config_input_override = { 'root.TAGMODE': { @@ -393,12 +396,21 @@ 'root.LED_COUNT': { 'input-type': 'number' }, - 'root.WLAN.SSID': { + 'root.WIFI.SSID': { 'input-type': 'text' }, - 'root.WLAN.PASSPHRASE': { + 'root.WIFI.PASSPHRASE': { 'input-type': 'text' }, + 'root.WIFI.SECURITY': { + 'element': 'select', + 'values': { + 'open': 'Open', + 'wpa_wpa2': 'WPA/WPA2 (PSK Mixed)', + 'wpa3': 'WPA3 (SAE AES)', + 'wpa2_wpa3': 'WPA2/WPA3 (PSK AES)' + } + }, 'root.VOLUME_MAX': { 'input-type': 'number' }, diff --git a/software/src/main.py b/software/src/main.py index 8ed430e..cae2b1f 100644 --- a/software/src/main.py +++ b/software/src/main.py @@ -36,19 +36,19 @@ hwconfig.board_init() machine.mem32[0x40030000 + 0x00] = 0x10 -def setup_wifi(ssid='', passphrase='', sec=network.WLAN.SEC_WPA2_WPA3): +def setup_wifi(ssid='', passphrase='', security=network.WLAN.SEC_WPA_WPA2): network.hostname("TonberryPico") if ssid is None or ssid == '': apname = f"TonberryPicoAP_{machine.unique_id().hex()}" print(f"Create AP {apname}") wlan = network.WLAN(network.WLAN.IF_AP) - wlan.config(ssid=apname, security=wlan.SEC_OPEN) + wlan.config(ssid=apname, password=passphrase if passphrase is not None else '', security=security) wlan.active(True) else: print(f"Connect to SSID {ssid} with passphrase {passphrase}...") wlan = network.WLAN() wlan.active(True) - wlan.connect(ssid, passphrase if passphrase is not None else '', security=sec) + wlan.connect(ssid, passphrase if passphrase is not None else '', security=security) # configure power management wlan.config(pm=network.WLAN.PM_PERFORMANCE) @@ -86,9 +86,19 @@ def run(): np.fill((0, 0, led_max)) np.write() # Force default access point - setup_wifi('', '') + setup_wifi('', '', network.WLAN.SEC_OPEN) else: - setup_wifi(config.get_wifi_ssid(), config.get_wifi_passphrase()) + secstring = config.get_wifi_security() + security = network.WLAN.SEC_WPA_WPA2 + if secstring == 'open': + security = network.WLAN.SEC_OPEN + elif secstring == 'wpa_wpa2': + security = network.WLAN.SEC_WPA_WPA2 + elif secstring == 'wpa3': + security = network.WLAN.SEC_WPA3 + elif secstring == 'wpa2_wpa3': + security = network.WLAN.SEC_WPA2_WPA3 + setup_wifi(config.get_wifi_ssid(), config.get_wifi_passphrase(), security) # Setup MP3 player with SDContext(mosi=hwconfig.SD_DI, miso=hwconfig.SD_DO, sck=hwconfig.SD_SCK, ss=hwconfig.SD_CS, diff --git a/software/src/utils/config.py b/software/src/utils/config.py index 6584cba..629a0fd 100644 --- a/software/src/utils/config.py +++ b/software/src/utils/config.py @@ -26,6 +26,7 @@ class Configuration: 'WIFI': { 'SSID': '', 'PASSPHRASE': '', + 'SECURITY': 'wpa_wpa2', }, 'VOLUME_MAX': 255, 'VOLUME_BOOT': 16, @@ -100,6 +101,9 @@ class Configuration: def get_wifi_passphrase(self) -> str: return self._get('WIFI')['PASSPHRASE'] + def get_wifi_security(self) -> str: + return self._get('WIFI')['SECURITY'] + def get_volume_max(self) -> int: return self._get('VOLUME_MAX') @@ -126,6 +130,9 @@ class Configuration: self._validate(self.DEFAULT_CONFIG, config) if 'TAGMODE' in config and config['TAGMODE'] not in ['tagremains', 'tagstartstop']: raise ValueError("Invalid TAGMODE: Must be 'tagremains' or 'tagstartstop'") + if 'WLAN' in config and 'SECURITY' in config['WLAN'] and \ + config['WLAN']['SECURITY'] not in ['open', 'wpa_wpa2', 'wpa3', 'wpa2_wpa3']: + raise ValueError("Invalid WLAN SECURITY: Must be 'open', 'wpa_wpa2', 'wpa3' or 'wpa2_wpa3'") self._merge_configs(self.config, config) self.config = config self._save()