Skip to content
Snippets Groups Projects
Commit b849bd4d authored by ave's avatar ave Committed by dx
Browse files

Add w1f1 app & replace wifi in settings menu

parent c56c9bdc
Branches
Tags
No related merge requests found
from st3m.application import Application, ApplicationContext
from st3m.input import InputState
from st3m.goose import Optional
from st3m.ui.view import ViewManager
from ctx import Context
import network
import leds
import os
import json
import math
from .k3yboard import TextInputModel, KeyboardView
class WifiApp(Application):
WIFI_CONFIG_FILE = "/flash/w1f1_config.json"
SETTINGS_JSON_FILE = "/flash/settings.json"
def __init__(self, app_ctx: ApplicationContext) -> None:
super().__init__(app_ctx)
self._petal_pressed = {}
self._nearby_wlans = []
self._status_text = "scanning"
self._error_text = ""
self._wlan_offset = 0
self._is_connecting = False
self._waiting_for_password = False
self._password_model = TextInputModel("")
if os.path.exists(self.WIFI_CONFIG_FILE):
with open(self.WIFI_CONFIG_FILE) as f:
self._wifi_config = json.load(f)
else:
self._wifi_config = {
"config_version": 2,
"networks": {
"Example SSID": {"psk": "Example PSK"},
"Camp2023-open": {"psk": None},
},
}
with open(self.WIFI_CONFIG_FILE, "w") as f:
json.dump(self._wifi_config, f)
def on_enter(self, vm: Optional[ViewManager]) -> None:
super().on_enter(vm)
self._connection_timer = 10
self._scan_timer = 0
self._iface = network.WLAN(network.STA_IF)
self._current_ssid = None
self._current_psk = None
self.input._ignore_pressed()
# TODO: big error display
def draw(self, ctx: Context) -> None:
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.font = ctx.get_font_name(8)
ctx.rgb(0, 0, 0).rectangle(-120, -90, 240, 180).fill()
ctx.rgb(0.2, 0.2, 0.2).rectangle(-120, -120, 240, 30).fill()
ctx.rgb(0.2, 0.2, 0.2).rectangle(-120, 90, 240, 30).fill()
ctx.font_size = 15
current_ssid = self._iface.config("ssid")
ctx.save()
ctx.rgb(1, 1, 1)
if self._iface.active():
ctx.rgb(0, 1, 0)
else:
ctx.rgb(1, 0, 0)
ctx.move_to(0, -105)
ctx.text("^")
ctx.move_to(0, -100)
ctx.text("toggle wlan")
ctx.restore()
ctx.rgb(1, 1, 1)
ctx.move_to(0, 100)
ctx.text(self._status_text)
wlan_draw_offset = self._wlan_offset * -20
for wlan in self._nearby_wlans:
ssid = wlan[0].decode()
if (
ssid == current_ssid
and self._iface.active()
and self._iface.isconnected()
):
ctx.rgb(0, 1, 0)
elif ssid == self._is_connecting:
ctx.rgb(0, 0, 1)
elif ssid in self._wifi_config["networks"]:
ctx.rgb(1, 1, 0)
else:
ctx.rgb(1, 1, 1)
if math.fabs(wlan_draw_offset) > 90:
wlan_draw_offset += 20
continue
if self._nearby_wlans[self._wlan_offset] == wlan:
ctx.font_size = 25
else:
ctx.font_size = 15
ctx.move_to(0, wlan_draw_offset)
ctx.text(ssid)
# TODO: maybe add signal indicator?
# https://fonts.google.com/icons?selected=Material+Icons+Outlined:network_wifi_1_bar:&icon.query=network+wifi&icon.set=Material+Icons
# draw a key next to wifi if it isn't open
if wlan[4] != 0:
ctx.save()
ssid_width = ctx.text_width(ssid)
ctx.font = "Material Icons"
ctx.text_align = ctx.LEFT
ctx.move_to((ssid_width / 2) + 5, wlan_draw_offset + 2)
ctx.text("\ue897")
ctx.restore()
wlan_draw_offset += 20
def set_direction_leds(self, direction, r, g, b):
if direction == 0:
leds.set_rgb(39, r, g, b)
else:
leds.set_rgb((direction * 4) - 1, r, g, b)
leds.set_rgb(direction * 4, r, g, b)
leds.set_rgb((direction * 4) + 1, r, g, b)
def on_exit(self) -> None:
leds.set_all_rgb(0, 0, 0)
leds.update()
def scan_wifi(self):
# skip hidden WLANs
self._nearby_wlans = [
wlan for wlan in self._iface.scan() if not wlan[5] and wlan[0]
]
# TODO: sort by known, then signal strength
print(self._nearby_wlans)
def update_settings_json(self, ssid: str, psk: str) -> None:
# weirdo case
if os.path.exists(self.SETTINGS_JSON_FILE):
with open(self.SETTINGS_JSON_FILE) as f:
settings_json = json.load(f)
else:
settings_json = {"system": {}}
if "wifi" not in settings_json["system"]:
settings_json["system"]["wifi"] = {
"enabled": True,
"ssid": "Camp2023-open",
"psk": None,
}
# clean up old config
if "camp_wifi_enabled" in settings_json["system"]:
del settings_json["system"]["camp_wifi_enabled"]
settings_json["system"]["wifi"]["ssid"] = ssid
settings_json["system"]["wifi"]["psk"] = psk
with open(self.SETTINGS_JSON_FILE, "w") as f:
json.dump(settings_json, f)
def add_to_config_json(self, ssid: str, psk: str) -> None:
self._wifi_config["networks"][ssid] = {"psk": psk}
with open(self.WIFI_CONFIG_FILE, "w") as f:
json.dump(self._wifi_config, f)
def connect_wifi(self, ssid: str, psk: str = None) -> None:
if ssid in self._wifi_config["networks"]:
psk = self._wifi_config["networks"][ssid]["psk"]
self._current_ssid = ssid
self._current_psk = psk
try:
self._is_connecting = ssid
self._iface.connect(
ssid,
psk,
)
self._status_text = "connecting"
except OSError as e:
self._status_text = str(e)
self._is_connecting = False
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms)
leds.set_all_rgb(0, 0, 0)
if self.input.buttons.app.left.pressed and self._wlan_offset > 0:
self._wlan_offset -= 1
elif (
self.input.buttons.app.right.pressed
and self._wlan_offset < len(self._nearby_wlans) - 1
):
self._wlan_offset += 1
if not self._nearby_wlans and self._iface.active() and self._scan_timer <= 0:
self._status_text = "scanning"
self.scan_wifi()
self._wlan_offset = 0
self._status_text = "ready"
self._scan_timer = 1
if not self._nearby_wlans:
self._iface.disconnect()
if not self._nearby_wlans:
self._scan_timer -= delta_ms / 1000
if ins.captouch.petals[0].pressed:
if not self._petal_pressed.get(0, False):
self._iface.active(not self._iface.active())
if not self._iface.active():
self._nearby_wlans = []
else:
self._status_text = "scanning"
self._petal_pressed[0] = True
else:
self._petal_pressed[0] = False
if self._iface.active():
self.set_direction_leds(0, 0, 1, 0)
else:
self.set_direction_leds(0, 1, 0, 0)
self._status_text = "wlan off"
if (
self.input.buttons.app.middle.pressed
and self._iface.active()
and self._nearby_wlans
):
hovered_network = self._nearby_wlans[self._wlan_offset]
ssid = hovered_network[0].decode()
if self._iface.isconnected():
self._iface.disconnect()
# network[4] = security level, 0 = open
if ssid in self._wifi_config["networks"] or hovered_network[4] == 0:
self.connect_wifi(ssid)
else:
self._waiting_for_password = True
self.vm.push(KeyboardView(self._password_model))
if self._waiting_for_password and (
not self.vm._history or not isinstance(self.vm._history[-1], WifiApp)
):
ssid = self._nearby_wlans[self._wlan_offset][0].decode()
psk = self._password_model.text
print(ssid, psk)
self.connect_wifi(ssid, psk)
self._password_model = TextInputModel("")
self._waiting_for_password = False
if self._is_connecting:
self._connection_timer -= delta_ms / 1000
if self._iface.isconnected():
self._connection_timer = 10
self._is_connecting = False
if self._current_ssid:
self.update_settings_json(self._current_ssid, self._current_psk)
if self._current_ssid not in self._wifi_config["networks"]:
self.add_to_config_json(self._current_ssid, self._current_psk)
elif self._connection_timer <= 0:
self._iface.disconnect()
self._status_text = "conn timed out"
self._is_connecting = False
if self._iface.isconnected():
self._status_text = "connected"
leds.update()
# For running with `mpremote run`:
if __name__ == "__main__":
import st3m.run
st3m.run.run_view(WifiApp(ApplicationContext()))
[app]
name = "WiFi"
menu = "Hidden"
[entry]
class = "WifiApp"
[metadata]
author = "ave"
license = "LGPL-3.0-only"
url = "https://git.flow3r.garden/flow3r/flow3r-firmware"
description = "Lets you use multiple wireless networks."
version = 4
# code from https://git.flow3r.garden/baldo/k3yboard
# LGPL-v3-only, by baldo, 2023
from ctx import Context
import st3m.run
from st3m import Responder, InputState
from st3m.application import Application, ApplicationContext
from st3m.goose import ABCBase, Enum
from st3m.ui.view import BaseView, ViewManager
from st3m.utils import tau
class Model(ABCBase):
"""
Common base-class for models holding state that can be used for rendering views.
"""
def __init__(self):
pass
class TextInputModel(Model):
"""
Model used for rendering the TextInputView. Holds the current input.
The input is split into the part left and the part right of the cursor. The input candidate is a character that
might be added to the input next and is displayed at the position of the cursor. This is used to give viusal
feedback while toggling through multiple characters inside a input group (associated with a petal).
"""
class CursorDirection(Enum):
LEFT = -1
RIGHT = 1
def __init__(
self, input_left: str = "", input_right: str = "", input_candidate: str = ""
) -> None:
super().__init__()
self._input_left = input_left
self._input_right = input_right
self.input_candidate = input_candidate
@property
def text(self) -> str:
"""
The complete input string in its current state.
"""
return self._input_left + self._input_right
@property
def input_left(self) -> str:
return self._input_left
@property
def input_right(self) -> str:
return self._input_right
def move_cursor(self, direction: self.CursorDirection) -> None:
"""
Moves the cursor one step in specified direction. Any pending input will be committed beforehand.
"""
self.commit_input()
if direction == self.CursorDirection.LEFT:
self._input_right = self._input_left[-1:] + self._input_right
self._input_left = self._input_left[:-1]
elif direction == self.CursorDirection.RIGHT:
self._input_left = self._input_left + self._input_right[0:1]
self._input_right = self._input_right[1:]
def add_input_character(self, char: str) -> None:
"""
Adds an input character at the current cursor position.
"""
self._input_left += char
self.input_candidate = ""
def delete_input_character(self) -> None:
"""
Deletes the character left to the cursor (if any).
If an input candidate is pending, it will be removed instead.
"""
if self.input_candidate == "":
self._input_left = self._input_left[:-1]
self.input_candidate = ""
def commit_input(self) -> None:
"""
Adds the pending input candidate (if any) to input left of the cursor.
"""
self.add_input_character(self.input_candidate)
class TextInputFieldView(Responder):
"""
Displays the current text input and cursor of a keyboard.
"""
def __init__(
self, model: TextInputModel, cursor_blink_duration_ms: float = 500
) -> None:
super().__init__()
self._model = model
self._cursor_blink_duration_ms = cursor_blink_duration_ms
self._cursor_timer_ms = 0
def draw_cursor(self, ctx: Context) -> None:
if self._cursor_blink_duration_ms < self._cursor_timer_ms:
return
ctx.begin_path()
ctx.rgb(0.0, 0.2, 1.0).rectangle(-1.0, -15.0, 2.0, 28.0).fill()
ctx.close_path()
def draw_text_input(self, ctx: Context) -> None:
ctx.begin_path()
cursor_offset = 1.5
ctx.text_baseline = ctx.MIDDLE
ctx.font_size = 24
left_input_width = ctx.text_width(self._model.input_left)
input_candidate_width = ctx.text_width(self._model.input_candidate)
right_input_width = ctx.text_width(self._model.input_right)
ctx.gray(0.2).rectangle(
-1.0 - cursor_offset - input_candidate_width - left_input_width,
ctx.font_size / 2.4,
left_input_width
+ input_candidate_width
+ right_input_width
+ 2 * cursor_offset
+ 2 * 1.0,
2,
).fill()
ctx.text_align = ctx.END
ctx.gray(1.0).move_to(-cursor_offset - input_candidate_width, 0).text(
self._model.input_left
)
ctx.text_align = ctx.END
ctx.rgb(0.0, 0.2, 1.0).move_to(-cursor_offset, 0).text(
self._model.input_candidate
)
ctx.text_align = ctx.START
ctx.gray(1.0).move_to(cursor_offset, 0).text(self._model.input_right)
ctx.close_path()
def draw(self, ctx: Context) -> None:
ctx.begin_path()
self.draw_text_input(ctx)
self.draw_cursor(ctx)
ctx.close_path()
def think(self, ins: InputState, delta_ms: int) -> None:
self._cursor_timer_ms = (self._cursor_timer_ms + delta_ms) % (
2 * self._cursor_blink_duration_ms
)
class InputControlsModel(Model):
"""
Model used for rendering the InputControlsView.
Holds the current active input and control groups (icons displayed in a ring around the edge of the screen).
Input groups are groups of characters to toggle through to select the character to input.
Control groups are groups of icons to control the behaviour of the keyboard.
"""
def __init__(
self,
input_groups: list[list[str]],
control_groups: list[list[str]],
active_input_group: int = 0,
) -> None:
super().__init__()
self._input_groups = input_groups
self._control_groups = control_groups
self._active_input_control_group = active_input_group
@property
def active_input_control_group(self):
return self._active_input_control_group
def select_input_control_group(self, group: int) -> None:
self._active_input_control_group = group
@property
def active_input_groups(self) -> list[str]:
return self._input_groups[self._active_input_control_group]
@property
def active_control_groups(self) -> list[str]:
return self._control_groups[self._active_input_control_group]
class InputControlsView(Responder):
"""
Shows a ring of controls and input characters to choose from around the edge.
"""
def __init__(self, model: InputControlsModel) -> None:
super().__init__()
self._model = model
def draw_input_group(self, ctx: Context, group: int) -> None:
inputs = self._model.active_input_groups[group]
ctx.begin_path()
bottom_input_group = 2 <= group <= 3
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.font_size = 18.0
ctx.gray(0.6)
angle_offset = tau / 5.0 / 10
angle = group * tau / 5.0 - angle_offset * (len(inputs) - 1) / 2.0
for input in reversed(inputs) if bottom_input_group else inputs:
ctx.save()
ctx.rotate(angle)
ctx.translate(0, -109)
if bottom_input_group:
ctx.rotate(tau / 2)
ctx.move_to(0, 0)
ctx.text(input)
ctx.restore()
angle += angle_offset
ctx.close_path()
def draw_control_group(self, ctx, group: int) -> None:
controls = self._model.active_control_groups[group]
ctx.begin_path()
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.font_size = 18.0
ctx.gray(0.6)
ctx.font = "Material Icons"
angle_offset = tau / 5.0 / 10
angle = (group + 0.5) * tau / 5.0 - angle_offset * (len(controls) - 1) / 2.0
for control in controls:
ctx.save()
ctx.rotate(angle)
ctx.translate(0, -109)
ctx.rotate(-angle)
ctx.move_to(0, 0)
ctx.text(control)
ctx.restore()
angle += angle_offset
ctx.close_path()
def draw(self, ctx: Context) -> None:
ctx.begin_path()
ctx.line_width = 4.0
ctx.gray(0).arc(0, 0, 98, 0, tau, 0).stroke()
ctx.line_width = 24.0
ctx.gray(0.1).arc(0, 0, 110, 0, tau, 0).stroke()
ctx.line_width = 2.0
ctx.gray(0.3).arc(0, 0, 99, 0, tau, 0).stroke()
for i in range(0, len(self._model.active_input_groups)):
self.draw_input_group(ctx, i)
for i in range(0, len(self._model.active_control_groups)):
self.draw_control_group(ctx, i)
ctx.close_path()
def think(self, ins: InputState, delta_ms: int) -> None:
pass
class KeyboardView(BaseView):
class ControlPetal(Enum):
SPECIAL_CHARACTERS = 1
BACKSPACE = 3
SPACE = 5
CAPSLOCK = 7
NUMLOCK = 9
class InputControlGroup(Enum):
LOWERCASE_LETTERS = 0
UPPERCASE_LETTERS = 1
NUMBERS = 2
SPECIAL_CHARACTERS = 3
def __init__(self, model: TextInputModel) -> None:
super().__init__()
self._last_input_group_press = -1
self._last_input_group_character = -1
self._time_since_last_input_group_press = 0
self._input_group_timeout = 1000
self._text_input_model = model
self._text_input_view = TextInputFieldView(self._text_input_model)
self._input_controls_model = InputControlsModel(
[
[
"fghij",
"klmno",
"uvwxyz",
"pqrst",
"abcde",
],
[
"FGHIJ",
"KLMNO",
"UVWXYZ",
"PQRST",
"ABCDE",
],
[
"34",
"56",
"90",
"78",
"12",
],
[
".,!?:;",
"'\"@#~",
"%$&<>\\",
"+-*/=",
"()[]{}",
],
],
[
[
"\ue9ef", # Special characters
"\ue14a", # Backspace
"\ue256", # Space
"\ue5ce", # Shift
"\ue400", # Num
],
[
"\ue9ef", # Special characters
"\ue14a", # Backspace
"\ue256", # Space
"\ue5cf", # Shift active
"\ue400", # Num
],
[
"\ue9ef", # Special characters
"\ue14a", # Backspace
"\ue256", # Space
"\ue264", # Text
"",
],
[
"",
"\ue14a", # Backspace
"\ue256", # Space
"\ue264", # Text
"\ue400", # Num
],
],
)
self._input_controls_view = InputControlsView(self._input_controls_model)
def on_enter(self, vm: Optional[ViewManager]) -> None:
super().on_enter(vm)
def on_exit(self) -> None:
super().on_exit()
self.reset_input_state()
def draw(self, ctx: Context) -> None:
ctx.begin_path()
ctx.gray(0).rectangle(-120, -120, 240, 240).fill()
self._text_input_view.draw(ctx)
self._input_controls_view.draw(ctx)
ctx.close_path()
def reset_input_state(self) -> None:
self._time_since_last_input_group_press = 0
self._last_input_group_press = -1
self._last_input_group_character = -1
self._text_input_model.input_candidate = ""
def add_input_character(self, char: str) -> None:
self._text_input_model.commit_input()
self._text_input_model.add_input_character(char)
self.reset_input_state()
def delete_input_character(self) -> None:
self._text_input_model.commit_input()
self._text_input_model.delete_input_character()
self.reset_input_state()
def commit_input(self) -> None:
self._text_input_model.commit_input()
self.reset_input_state()
def select_input_group(self, input_group) -> None:
self.commit_input()
self._input_controls_model.select_input_control_group(input_group)
self.reset_input_state()
def handle_shoulder_buttons(self) -> None:
if self.input.buttons.app.middle.pressed:
self.commit_input()
if self.vm:
self.vm.pop()
if self.input.buttons.app.left.pressed:
self._text_input_model.move_cursor(TextInputModel.CursorDirection.LEFT)
if self.input.buttons.app.right.pressed:
self._text_input_model.move_cursor(TextInputModel.CursorDirection.RIGHT)
def handle_control_inputs(self) -> None:
if self.input.captouch.petals[
self.ControlPetal.SPECIAL_CHARACTERS
].whole.pressed:
self.select_input_group(self.InputControlGroup.SPECIAL_CHARACTERS)
if self.input.captouch.petals[self.ControlPetal.BACKSPACE].whole.pressed:
self.delete_input_character()
if self.input.captouch.petals[self.ControlPetal.SPACE].whole.pressed:
self.add_input_character(" ")
if self.input.captouch.petals[self.ControlPetal.CAPSLOCK].whole.pressed:
self.select_input_group(
self.InputControlGroup.UPPERCASE_LETTERS
if self._input_controls_model.active_input_control_group
== self.InputControlGroup.LOWERCASE_LETTERS
else self.InputControlGroup.LOWERCASE_LETTERS
)
if self.input.captouch.petals[self.ControlPetal.NUMLOCK].whole.pressed:
self.select_input_group(self.InputControlGroup.NUMBERS)
def handle_input_groups(self, delta_ms: int) -> bool:
for i in range(0, 5):
if self.input.captouch.petals[i * 2].whole.pressed:
if (
self._last_input_group_press >= 0
and self._last_input_group_press != i
):
self.commit_input()
self._last_input_group_press = i
self._last_input_group_character = (
self._last_input_group_character + 1
) % len(self._input_controls_model.active_input_groups[i])
self._time_since_last_input_group_press = 0
self._text_input_model.input_candidate = (
self._input_controls_model.active_input_groups[i][
self._last_input_group_character
]
)
return
self._time_since_last_input_group_press += delta_ms
if (
self._last_input_group_press >= 0
and self._time_since_last_input_group_press > self._input_group_timeout
):
self.commit_input()
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms)
self._text_input_view.think(ins, delta_ms)
self._input_controls_view.think(ins, delta_ms)
self.handle_shoulder_buttons()
self.handle_control_inputs()
self.handle_input_groups(delta_ms)
class KeyboardDemoApp(Application):
def __init__(self, app_ctx: ApplicationContext) -> None:
super().__init__(app_ctx)
self._model = TextInputModel("Hello world!")
def draw(self, ctx: Context) -> None:
ctx.gray(0).rectangle(-120, -120, 240, 240).fill()
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
ctx.font_size = 24
ctx.gray(1).move_to(0, -50).text("Keyboard Demo")
ctx.font_size = 16
ctx.gray(1).move_to(0, -20).text("Press left button to edit")
ctx.font_size = 24
ctx.gray(1).move_to(0, 20).text("Current input:")
ctx.font_size = 16
ctx.gray(1).move_to(0, 50).text(self._model.text)
def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms) # Let Application do its thing
if self.input.buttons.app.middle.pressed:
self.vm.push(KeyboardView(self._model))
if __name__ == "__main__":
st3m.run.run_view(KeyboardDemoApp(ApplicationContext()))
...@@ -24,6 +24,7 @@ from st3m.goose import ( ...@@ -24,6 +24,7 @@ from st3m.goose import (
TYPE_CHECKING, TYPE_CHECKING,
) )
from st3m.ui.menu import MenuController, MenuItem, MenuItemBack, MenuItemForeground from st3m.ui.menu import MenuController, MenuItem, MenuItemBack, MenuItemForeground
from st3m.application import BundleMetadata, MenuItemAppLaunch
from st3m.ui.elements.menus import SimpleMenu from st3m.ui.elements.menus import SimpleMenu
from st3m.ui.view import ViewManager from st3m.ui.view import ViewManager
from st3m.utils import lerp, ease_out_cubic, reduce from st3m.utils import lerp, ease_out_cubic, reduce
...@@ -106,7 +107,7 @@ class TunableWidget(Responder): ...@@ -106,7 +107,7 @@ class TunableWidget(Responder):
class UnaryTunable(Tunable): class UnaryTunable(Tunable):
""" """
Basic implementation of a Tunable for single values. Most settings will are Basic implementation of a Tunable for single values. Most settings will be
UnaryTunables, with notable exceptions being things like lists or optional UnaryTunables, with notable exceptions being things like lists or optional
settings. settings.
...@@ -382,7 +383,7 @@ onoff_button_swap = OnOffTunable("Swap Buttons", "system.swap_buttons", False) ...@@ -382,7 +383,7 @@ onoff_button_swap = OnOffTunable("Swap Buttons", "system.swap_buttons", False)
onoff_debug = OnOffTunable("Debug Overlay", "system.debug", False) onoff_debug = OnOffTunable("Debug Overlay", "system.debug", False)
onoff_debug_touch = OnOffTunable("Touch Overlay", "system.debug_touch", False) onoff_debug_touch = OnOffTunable("Touch Overlay", "system.debug_touch", False)
onoff_show_tray = OnOffTunable("Show Icons", "system.show_icons", True) onoff_show_tray = OnOffTunable("Show Icons", "system.show_icons", True)
onoff_wifi = OnOffTunable("Enable WiFi", "system.wifi.enabled", False) onoff_wifi = OnOffTunable("Enable WiFi on Boot", "system.wifi.enabled", False)
str_wifi_ssid = StringTunable("WiFi SSID", "system.wifi.ssid", "Camp2023-open") str_wifi_ssid = StringTunable("WiFi SSID", "system.wifi.ssid", "Camp2023-open")
str_wifi_psk = ObfuscatedStringTunable("WiFi Password", "system.wifi.psk", None) str_wifi_psk = ObfuscatedStringTunable("WiFi Password", "system.wifi.psk", None)
str_hostname = StringTunable("Hostname", "system.hostname", "flow3r") str_hostname = StringTunable("Hostname", "system.hostname", "flow3r")
...@@ -403,21 +404,14 @@ if TYPE_CHECKING: ...@@ -403,21 +404,14 @@ if TYPE_CHECKING:
MenuStructureEntry = Union[UnaryTunable, Tuple[str, List["MenuStructureEntry"]]] MenuStructureEntry = Union[UnaryTunable, Tuple[str, List["MenuStructureEntry"]]]
MenuStructure = List[MenuStructureEntry] MenuStructure = List[MenuStructureEntry]
# WiFi submenu
wifi_settings: "MenuStructure" = [
onoff_wifi,
str_wifi_ssid,
str_wifi_psk,
str_hostname,
]
# Main settings menu # Main settings menu
settings_menu_structure: "MenuStructure" = [ settings_menu_structure: "MenuStructure" = [
onoff_show_tray, onoff_show_tray,
onoff_button_swap, onoff_button_swap,
onoff_debug, onoff_debug,
onoff_debug_touch, onoff_debug_touch,
("WiFi", wifi_settings), onoff_wifi,
MenuItemAppLaunch(BundleMetadata("/flash/sys/apps/w1f1")),
] ]
...@@ -474,12 +468,7 @@ def build_menu_recursive(items: "MenuStructure") -> SimpleMenu: ...@@ -474,12 +468,7 @@ def build_menu_recursive(items: "MenuStructure") -> SimpleMenu:
mib: MenuItem = MenuItemBack() mib: MenuItem = MenuItemBack()
positions: List[MenuItem] = [ positions: List[MenuItem] = [
mib, mib,
] + [ ] + [SettingsMenuItem(t) if isinstance(t, UnaryTunable) else t for t in items]
SettingsMenuItem(t)
if isinstance(t, UnaryTunable)
else MenuItemForeground(t[0], build_menu_recursive(t[1]))
for t in items
]
return SettingsMenu(positions) return SettingsMenu(positions)
......
...@@ -15,6 +15,7 @@ def setup_wifi() -> None: ...@@ -15,6 +15,7 @@ def setup_wifi() -> None:
assert iface assert iface
try: try:
if settings.str_wifi_ssid.value: if settings.str_wifi_ssid.value:
iface.disconnect()
iface.connect(settings.str_wifi_ssid.value, settings.str_wifi_psk.value) iface.connect(settings.str_wifi_ssid.value, settings.str_wifi_psk.value)
except OSError as e: except OSError as e:
log.error(f"Could not connect to wifi: {e}") log.error(f"Could not connect to wifi: {e}")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment