1- import os
21import time
32import lvgl as lv
43import _thread
54
65from mpos .apps import Activity , Intent
76from mpos .ui .keyboard import MposKeyboard
87
9- import mpos .config
8+ import mpos .apps
109from mpos .net .wifi_service import WifiService
1110
11+
1212class WiFi (Activity ):
13+ """
14+ WiFi settings app for MicroPythonOS.
15+
16+ This is a pure UI layer - all WiFi operations are delegated to WifiService.
17+ """
1318
14- prefs = None
15- saved_access_points = {}
1619 last_tried_ssid = ""
1720 last_tried_result = ""
18- have_network = True
19- try :
20- import network
21- except Exception as e :
22- have_network = False
2321
2422 scan_button_scan_text = "Rescan"
2523 scan_button_scanning_text = "Scanning..."
2624
27- scanned_ssids = []
25+ scanned_ssids = []
2826 busy_scanning = False
2927 busy_connecting = False
3028 error_timer = None
@@ -39,25 +37,25 @@ def onCreate(self):
3937 print ("wifi.py onCreate" )
4038 main_screen = lv .obj ()
4139 main_screen .set_style_pad_all (15 , 0 )
42- self .aplist = lv .list (main_screen )
43- self .aplist .set_size (lv .pct (100 ),lv .pct (75 ))
44- self .aplist .align (lv .ALIGN .TOP_MID ,0 , 0 )
45- self .error_label = lv .label (main_screen )
40+ self .aplist = lv .list (main_screen )
41+ self .aplist .set_size (lv .pct (100 ), lv .pct (75 ))
42+ self .aplist .align (lv .ALIGN .TOP_MID , 0 , 0 )
43+ self .error_label = lv .label (main_screen )
4644 self .error_label .set_text ("THIS IS ERROR TEXT THAT WILL BE SET LATER" )
47- self .error_label .align_to (self .aplist , lv .ALIGN .OUT_BOTTOM_MID ,0 , 0 )
45+ self .error_label .align_to (self .aplist , lv .ALIGN .OUT_BOTTOM_MID , 0 , 0 )
4846 self .error_label .add_flag (lv .obj .FLAG .HIDDEN )
49- self .add_network_button = lv .button (main_screen )
50- self .add_network_button .set_size (lv .SIZE_CONTENT ,lv .pct (15 ))
51- self .add_network_button .align (lv .ALIGN .BOTTOM_LEFT ,0 , 0 )
52- self .add_network_button .add_event_cb (self .add_network_callback ,lv .EVENT .CLICKED ,None )
53- self .add_network_button_label = lv .label (self .add_network_button )
47+ self .add_network_button = lv .button (main_screen )
48+ self .add_network_button .set_size (lv .SIZE_CONTENT , lv .pct (15 ))
49+ self .add_network_button .align (lv .ALIGN .BOTTOM_LEFT , 0 , 0 )
50+ self .add_network_button .add_event_cb (self .add_network_callback , lv .EVENT .CLICKED , None )
51+ self .add_network_button_label = lv .label (self .add_network_button )
5452 self .add_network_button_label .set_text ("Add network" )
5553 self .add_network_button_label .center ()
56- self .scan_button = lv .button (main_screen )
57- self .scan_button .set_size (lv .SIZE_CONTENT ,lv .pct (15 ))
58- self .scan_button .align (lv .ALIGN .BOTTOM_RIGHT ,0 , 0 )
59- self .scan_button .add_event_cb (self .scan_cb ,lv .EVENT .CLICKED ,None )
60- self .scan_button_label = lv .label (self .scan_button )
54+ self .scan_button = lv .button (main_screen )
55+ self .scan_button .set_size (lv .SIZE_CONTENT , lv .pct (15 ))
56+ self .scan_button .align (lv .ALIGN .BOTTOM_RIGHT , 0 , 0 )
57+ self .scan_button .add_event_cb (self .scan_cb , lv .EVENT .CLICKED , None )
58+ self .scan_button_label = lv .label (self .scan_button )
6159 self .scan_button_label .set_text (self .scan_button_scan_text )
6260 self .scan_button_label .center ()
6361 self .setContentView (main_screen )
@@ -66,11 +64,9 @@ def onResume(self, screen):
6664 print ("wifi.py onResume" )
6765 super ().onResume (screen )
6866
69- if not self . prefs :
70- self . prefs = mpos . config . SharedPreferences ( "com.micropythonos.system.wifiservice" )
67+ # Ensure WifiService has loaded saved networks
68+ WifiService . get_saved_networks ( )
7169
72- self .saved_access_points = self .prefs .get_dict ("access_points" )
73- print (f"loaded access points from preferences: { self .saved_access_points } " )
7470 if len (self .scanned_ssids ) == 0 :
7571 if WifiService .wifi_busy == False :
7672 WifiService .wifi_busy = True
@@ -83,34 +79,24 @@ def show_error(self, message):
8379 print (f"show_error: Displaying error: { message } " )
8480 self .update_ui_threadsafe_if_foreground (self .error_label .set_text , message )
8581 self .update_ui_threadsafe_if_foreground (self .error_label .remove_flag , lv .obj .FLAG .HIDDEN )
86- self .error_timer = lv .timer_create (self .hide_error ,5000 ,None )
82+ self .error_timer = lv .timer_create (self .hide_error , 5000 , None )
8783 self .error_timer .set_repeat_count (1 )
8884
8985 def hide_error (self , timer ):
90- self .update_ui_threadsafe_if_foreground (self .error_label .add_flag ,lv .obj .FLAG .HIDDEN )
86+ self .update_ui_threadsafe_if_foreground (self .error_label .add_flag , lv .obj .FLAG .HIDDEN )
9187
9288 def scan_networks_thread (self ):
9389 print ("scan_networks: Scanning for Wi-Fi networks" )
94- if self .have_network :
95- wlan = network .WLAN (network .STA_IF )
96- if not wlan .isconnected (): # restart WiFi hardware in case it's in a bad state
97- wlan .active (False )
98- wlan .active (True )
9990 try :
100- if self .have_network :
101- networks = wlan .scan ()
102- self .scanned_ssids = list (set (n [0 ].decode () for n in networks ))
103- else :
104- time .sleep (1 )
105- self .scanned_ssids = ["Home WiFi" , "Pretty Fly for a Wi Fi" , "Winternet is coming" , "The Promised LAN" ]
91+ self .scanned_ssids = WifiService .scan_networks ()
10692 print (f"scan_networks: Found networks: { self .scanned_ssids } " )
10793 except Exception as e :
10894 print (f"scan_networks: Scan failed: { e } " )
10995 self .show_error ("Wi-Fi scan failed" )
11096 # scan done:
11197 self .busy_scanning = False
11298 WifiService .wifi_busy = False
113- self .update_ui_threadsafe_if_foreground (self .scan_button_label .set_text ,self .scan_button_scan_text )
99+ self .update_ui_threadsafe_if_foreground (self .scan_button_label .set_text , self .scan_button_scan_text )
114100 self .update_ui_threadsafe_if_foreground (self .scan_button .remove_state , lv .STATE .DISABLED )
115101 self .update_ui_threadsafe_if_foreground (self .refresh_list )
116102
@@ -126,28 +112,35 @@ def start_scan_networks(self):
126112
127113 def refresh_list (self ):
128114 print ("refresh_list: Clearing current list" )
129- self .aplist .clean () # this causes an issue with lost taps if an ssid is clicked that has been removed
115+ self .aplist .clean () # this causes an issue with lost taps if an ssid is clicked that has been removed
130116 print ("refresh_list: Populating list with scanned networks" )
131- for ssid in set (self .scanned_ssids + list (ssid for ssid in self .saved_access_points )):
117+
118+ # Combine scanned SSIDs with saved networks
119+ saved_networks = WifiService .get_saved_networks ()
120+ all_ssids = set (self .scanned_ssids + saved_networks )
121+
122+ for ssid in all_ssids :
132123 if len (ssid ) < 1 or len (ssid ) > 32 :
133124 print (f"Skipping too short or long SSID: { ssid } " )
134125 continue
135126 print (f"refresh_list: Adding SSID: { ssid } " )
136- button = self .aplist .add_button (None ,ssid )
137- button .add_event_cb (lambda e , s = ssid : self .select_ssid_cb (s ),lv .EVENT .CLICKED ,None )
127+ button = self .aplist .add_button (None , ssid )
128+ button .add_event_cb (lambda e , s = ssid : self .select_ssid_cb (s ), lv .EVENT .CLICKED , None )
129+
130+ # Determine status
138131 status = ""
139- if self . have_network :
140- wlan = network . WLAN ( network . STA_IF )
141- if wlan . isconnected () and wlan . config ( 'essid' ) == ssid :
142- status = "connected"
143- if status != "connected" :
144- if self . last_tried_ssid == ssid : # implies not connected because not wlan.isconnected()
145- status = self . last_tried_result
146- elif ssid in self . saved_access_points :
147- status = "saved"
148- label = lv .label (button )
132+ current_ssid = WifiService . get_current_ssid ()
133+ if current_ssid == ssid :
134+ status = "connected"
135+ elif self . last_tried_ssid == ssid :
136+ # Show last connection attempt result
137+ status = self . last_tried_result
138+ elif ssid in saved_networks :
139+ status = "saved"
140+
141+ label = lv .label (button )
149142 label .set_text (status )
150- label .align (lv .ALIGN .RIGHT_MID ,0 , 0 )
143+ label .align (lv .ALIGN .RIGHT_MID , 0 , 0 )
151144
152145 def add_network_callback (self , event ):
153146 print (f"add_network_callback clicked" )
@@ -159,36 +152,28 @@ def scan_cb(self, event):
159152 print ("scan_cb: Scan button clicked, refreshing list" )
160153 self .start_scan_networks ()
161154
162- def select_ssid_cb (self ,ssid ):
155+ def select_ssid_cb (self , ssid ):
163156 print (f"select_ssid_cb: SSID selected: { ssid } " )
164157 intent = Intent (activity_class = EditNetwork )
165158 intent .putExtra ("selected_ssid" , ssid )
166- intent .putExtra ("known_password" , self . findSavedPassword (ssid ))
159+ intent .putExtra ("known_password" , WifiService . get_network_password (ssid ))
167160 self .startActivityForResult (intent , self .edit_network_result_callback )
168-
161+
169162 def edit_network_result_callback (self , result ):
170163 print (f"EditNetwork finished, result: { result } " )
171164 if result .get ("result_code" ) is True :
172165 data = result .get ("data" )
173166 if data :
174167 ssid = data .get ("ssid" )
175- editor = self .prefs .edit ()
176168 forget = data .get ("forget" )
177169 if forget :
178- try :
179- del self .saved_access_points [ssid ]
180- editor .put_dict ("access_points" , self .saved_access_points )
181- editor .commit ()
182- self .refresh_list ()
183- except Exception as e :
184- print (f"WARNING: could not forget access point, maybe it wasn't remembered in the first place: { e } " )
185- else : # save or update
170+ WifiService .forget_network (ssid )
171+ self .refresh_list ()
172+ else :
173+ # Save or update the network
186174 password = data .get ("password" )
187175 hidden = data .get ("hidden" )
188- self .setPassword (ssid , password , hidden )
189- editor .put_dict ("access_points" , self .saved_access_points )
190- editor .commit ()
191- print (f"access points: { self .saved_access_points } " )
176+ WifiService .save_network (ssid , password , hidden )
192177 self .start_attempt_connecting (ssid , password )
193178
194179 def start_attempt_connecting (self , ssid , password ):
@@ -200,73 +185,47 @@ def start_attempt_connecting(self, ssid, password):
200185 else :
201186 self .busy_connecting = True
202187 _thread .stack_size (mpos .apps .good_stack_size ())
203- _thread .start_new_thread (self .attempt_connecting_thread , (ssid ,password ))
188+ _thread .start_new_thread (self .attempt_connecting_thread , (ssid , password ))
204189
205190 def attempt_connecting_thread (self , ssid , password ):
206- print (f"attempt_connecting_thread: Attempting to connect to SSID '{ ssid } ' with password ' { password } ' " )
207- result = "connected"
191+ print (f"attempt_connecting_thread: Attempting to connect to SSID '{ ssid } '" )
192+ result = "connected"
208193 try :
209- if self .have_network :
210- wlan = network .WLAN (network .STA_IF )
211- wlan .disconnect ()
212- wlan .connect (ssid ,password )
213- for i in range (10 ):
214- if wlan .isconnected ():
215- print (f"attempt_connecting: Connected to { ssid } after { i + 1 } seconds" )
216- break
217- print (f"attempt_connecting: Waiting for connection, attempt { i + 1 } /10" )
218- time .sleep (1 )
219- if not wlan .isconnected ():
220- result = "timeout"
194+ if WifiService .attempt_connecting (ssid , password ):
195+ result = "connected"
221196 else :
222- print ("Warning: not trying to connect because not self.have_network, just waiting a bit..." )
223- time .sleep (5 )
197+ result = "timeout"
224198 except Exception as e :
225199 print (f"attempt_connecting: Connection error: { e } " )
226- result = f"{ e } "
227- self .show_error ("Connecting to {ssid} failed!" )
200+ result = f"{ e } "
201+ self .show_error (f"Connecting to { ssid } failed!" )
202+
228203 print (f"Connecting to { ssid } got result: { result } " )
229204 self .last_tried_ssid = ssid
230205 self .last_tried_result = result
231- # also do a time sync, otherwise some apps (Nostr Wallet Connect) won't work:
232- if self . have_network and wlan . isconnected ():
233- mpos . time . sync_time ()
234- self .busy_connecting = False
206+
207+ # Note: Time sync is handled by WifiService.attempt_connecting()
208+
209+ self .busy_connecting = False
235210 self .update_ui_threadsafe_if_foreground (self .scan_button_label .set_text , self .scan_button_scan_text )
236211 self .update_ui_threadsafe_if_foreground (self .scan_button .remove_state , lv .STATE .DISABLED )
237212 self .update_ui_threadsafe_if_foreground (self .refresh_list )
238213
239- def findSavedPassword (self , ssid ):
240- ap = self .saved_access_points .get (ssid )
241- if ap :
242- return ap .get ("password" )
243- return None
244-
245- def setPassword (self , ssid , password , hidden = False ):
246- ap = self .saved_access_points .get (ssid )
247- if ap :
248- ap ["password" ] = password
249- if hidden is True :
250- ap ["hidden" ] = True
251- return
252- # if not found, then add it:
253- self .saved_access_points [ssid ] = { "password" : password , "hidden" : hidden }
254-
255214
256215class EditNetwork (Activity ):
257216
258217 selected_ssid = None
259218
260219 # Widgets:
261220 ssid_ta = None
262- password_ta = None
221+ password_ta = None
263222 hidden_cb = None
264- keyboard = None
265- connect_button = None
266- cancel_button = None
223+ keyboard = None
224+ connect_button = None
225+ cancel_button = None
267226
268227 def onCreate (self ):
269- password_page = lv .obj ()
228+ password_page = lv .obj ()
270229 password_page .set_style_pad_all (0 , lv .PART .MAIN )
271230 password_page .set_flex_flow (lv .FLEX_FLOW .COLUMN )
272231 self .selected_ssid = self .getIntent ().extras .get ("selected_ssid" )
@@ -275,31 +234,31 @@ def onCreate(self):
275234 # SSID:
276235 if self .selected_ssid is None :
277236 print ("No ssid selected, the user should fill it out." )
278- label = lv .label (password_page )
237+ label = lv .label (password_page )
279238 label .set_text (f"Network name:" )
280- self .ssid_ta = lv .textarea (password_page )
239+ self .ssid_ta = lv .textarea (password_page )
281240 self .ssid_ta .set_width (lv .pct (90 ))
282241 self .ssid_ta .set_style_margin_left (5 , lv .PART .MAIN )
283242 self .ssid_ta .set_one_line (True )
284243 self .ssid_ta .set_placeholder_text ("Enter the SSID" )
285- self .keyboard = MposKeyboard (password_page )
244+ self .keyboard = MposKeyboard (password_page )
286245 self .keyboard .set_textarea (self .ssid_ta )
287246 self .keyboard .add_flag (lv .obj .FLAG .HIDDEN )
288-
247+
289248 # Password:
290- label = lv .label (password_page )
249+ label = lv .label (password_page )
291250 if self .selected_ssid is None :
292251 label .set_text ("Password:" )
293252 else :
294253 label .set_text (f"Password for '{ self .selected_ssid } ':" )
295- self .password_ta = lv .textarea (password_page )
254+ self .password_ta = lv .textarea (password_page )
296255 self .password_ta .set_width (lv .pct (90 ))
297256 self .password_ta .set_style_margin_left (5 , lv .PART .MAIN )
298257 self .password_ta .set_one_line (True )
299258 if known_password :
300259 self .password_ta .set_text (known_password )
301260 self .password_ta .set_placeholder_text ("Password" )
302- self .keyboard = MposKeyboard (password_page )
261+ self .keyboard = MposKeyboard (password_page )
303262 self .keyboard .set_textarea (self .password_ta )
304263 self .keyboard .add_flag (lv .obj .FLAG .HIDDEN )
305264
@@ -316,24 +275,24 @@ def onCreate(self):
316275 buttons .set_style_border_width (0 , lv .PART .MAIN )
317276 # Delete button
318277 if self .selected_ssid :
319- self .forget_button = lv .button (buttons )
278+ self .forget_button = lv .button (buttons )
320279 self .forget_button .align (lv .ALIGN .LEFT_MID , 0 , 0 )
321280 self .forget_button .add_event_cb (self .forget_cb , lv .EVENT .CLICKED , None )
322- label = lv .label (self .forget_button )
281+ label = lv .label (self .forget_button )
323282 label .set_text ("Forget" )
324283 label .center ()
325284 # Close button
326- self .cancel_button = lv .button (buttons )
285+ self .cancel_button = lv .button (buttons )
327286 self .cancel_button .center ()
328287 self .cancel_button .add_event_cb (lambda * args : self .finish (), lv .EVENT .CLICKED , None )
329- label = lv .label (self .cancel_button )
288+ label = lv .label (self .cancel_button )
330289 label .set_text ("Close" )
331290 label .center ()
332291 # Connect button
333292 self .connect_button = lv .button (buttons )
334293 self .connect_button .align (lv .ALIGN .RIGHT_MID , 0 , 0 )
335- self .connect_button .add_event_cb (self .connect_cb ,lv .EVENT .CLICKED ,None )
336- label = lv .label (self .connect_button )
294+ self .connect_button .add_event_cb (self .connect_cb , lv .EVENT .CLICKED , None )
295+ label = lv .label (self .connect_button )
337296 label .set_text ("Connect" )
338297 label .center ()
339298
0 commit comments