WifiService
MicroPythonOS provides a centralized WiFi management service called WifiService that handles WiFi connections, network scanning, and credential storage. It's designed to work alongside ConnectivityManager for comprehensive network management.
Overview
WifiService provides:
- Auto-connect on boot - Automatically connects to saved networks when device starts
- Network scanning - Scan for available WiFi networks
- Credential management - Save, retrieve, and forget network passwords
- Hidden network support - Connect to networks that don't broadcast SSID
- Concurrent access locking - Thread-safe WiFi operations
- Desktop simulation - Mock WiFi for desktop testing
- ADC2 compatibility - Temporarily disable WiFi for ESP32-S3 ADC2 operations
Quick Start
Checking Connection Status
from mpos import WifiService
# Check if WiFi is connected
if WifiService.is_connected():
ssid = WifiService.get_current_ssid()
print(f"Connected to: {ssid}")
else:
print("Not connected to WiFi")
Scanning for Networks
from mpos import WifiService
# Scan for available networks
networks = WifiService.scan_networks()
for ssid in networks:
print(f"Found network: {ssid}")
Note: scan_networks() manages the busy flag automatically. If WiFi is already busy (e.g., connecting), it returns an empty list.
Connecting to a Network
from mpos import WifiService
# Save network credentials first
WifiService.save_network("MyNetwork", "password123")
# Connect to the network
success = WifiService.attempt_connecting("MyNetwork", "password123")
if success:
print("Connected!")
else:
print("Connection failed")
Managing Saved Networks
from mpos import WifiService
# Save a network
WifiService.save_network("HomeWiFi", "mypassword")
# Save a hidden network
WifiService.save_network("HiddenNetwork", "secret", hidden=True)
# Get list of saved networks
saved = WifiService.get_saved_networks()
print(f"Saved networks: {saved}")
# Get password for a network
password = WifiService.get_network_password("HomeWiFi")
# Forget a network
WifiService.forget_network("OldNetwork")
Common Patterns
WiFi Settings Screen
from mpos import Activity, WifiService
import lvgl as lv
class WifiSettingsActivity(Activity):
def onCreate(self):
self.screen = lv.obj()
# Status label
self.status = lv.label(self.screen)
self.update_status()
self.status.align(lv.ALIGN.TOP_MID, 0, 10)
# Scan button
scan_btn = lv.button(self.screen)
scan_btn.set_size(120, 40)
scan_btn.align(lv.ALIGN.TOP_MID, 0, 50)
scan_label = lv.label(scan_btn)
scan_label.set_text("Scan")
scan_label.center()
scan_btn.add_event_cb(self.on_scan, lv.EVENT.CLICKED, None)
# Network list
self.network_list = lv.list(self.screen)
self.network_list.set_size(280, 150)
self.network_list.align(lv.ALIGN.CENTER, 0, 30)
self.setContentView(self.screen)
def update_status(self):
if WifiService.is_connected():
ssid = WifiService.get_current_ssid()
self.status.set_text(f"Connected: {ssid}")
else:
self.status.set_text("Not connected")
def on_scan(self, event):
if WifiService.is_busy():
print("WiFi is busy")
return
# Clear list
self.network_list.clean()
# Scan for networks
networks = WifiService.scan_networks()
saved = WifiService.get_saved_networks()
for ssid in networks:
btn = self.network_list.add_button(None, ssid)
if ssid in saved:
# Mark saved networks
btn.set_style_bg_color(lv.color_hex(0x4CAF50), 0)
btn.add_event_cb(
lambda e, s=ssid: self.on_network_selected(s),
lv.EVENT.CLICKED,
None
)
def on_network_selected(self, ssid):
# Show password dialog or connect if already saved
password = WifiService.get_network_password(ssid)
if password:
success = WifiService.attempt_connecting(ssid, password)
if success:
self.update_status()
Background Auto-Connect
WifiService automatically handles auto-connect on boot. This is typically started from main.py:
import _thread
from mpos import WifiService
import mpos.apps
# Start auto-connect in background thread
_thread.stack_size(mpos.apps.good_stack_size())
_thread.start_new_thread(WifiService.auto_connect, ())
Auto-connect behavior: 1. Loads saved networks from SharedPreferences 2. Scans for available networks 3. Tries to connect to saved networks (strongest signal first) 4. Also tries hidden networks that don't appear in scan 5. Syncs time via NTP on successful connection 6. Disables WiFi if no networks found (power saving)
Temporarily Disabling WiFi for ADC2
On ESP32-S3, ADC2 pins (GPIO11-20) don't work when WiFi is active. WifiService provides methods to temporarily disable WiFi:
from mpos import WifiService
def read_adc2_sensor():
"""Read from ADC2 pin which requires WiFi to be disabled."""
try:
# Disable WiFi (raises RuntimeError if WiFi is busy)
was_connected = WifiService.temporarily_disable()
# Now safe to read ADC2
from machine import ADC, Pin
adc = ADC(Pin(15)) # GPIO15 is on ADC2
value = adc.read()
return value
finally:
# Re-enable WiFi (reconnects if was connected)
WifiService.temporarily_enable(was_connected)
Important: Always call temporarily_enable() in a finally block to ensure WiFi is re-enabled.
API Reference
Connection Functions
WifiService.connect(network_module=None)
Scan for available networks and connect to the first saved network found.
Parameters:
- network_module - Network module for dependency injection (testing)
Returns:
- bool - True if successfully connected, False otherwise
Example:
if WifiService.connect():
print("Connected to a saved network")
WifiService.attempt_connecting(ssid, password, network_module=None, time_module=None)
Attempt to connect to a specific WiFi network.
Parameters:
- ssid (str) - Network SSID to connect to
- password (str) - Network password
- network_module - Network module for dependency injection (testing)
- time_module - Time module for dependency injection (testing)
Returns:
- bool - True if successfully connected, False otherwise
Behavior:
- Waits up to 10 seconds for connection
- Syncs time via NTP on success
- Returns False if WiFi is disabled during connection
Example:
success = WifiService.attempt_connecting("MyNetwork", "password123")
WifiService.auto_connect(network_module=None, time_module=None)
Auto-connect to a saved WiFi network on boot.
Parameters:
- network_module - Network module for dependency injection (testing)
- time_module - Time module for dependency injection (testing)
Behavior: - Loads saved networks from SharedPreferences - Checks if WiFi is busy before proceeding - Tries saved networks in order of signal strength - Also tries hidden networks - Disables WiFi if no connection made (power saving)
Example:
import _thread
_thread.start_new_thread(WifiService.auto_connect, ())
WifiService.disconnect(network_module=None)
Disconnect from current WiFi network and disable WiFi.
Parameters:
- network_module - Network module for dependency injection (testing)
Example:
WifiService.disconnect()
WifiService.is_connected(network_module=None)
Check if WiFi is currently connected.
Parameters:
- network_module - Network module for dependency injection (testing)
Returns:
- bool - True if connected, False otherwise
Note: Returns False if WiFi operations are in progress (wifi_busy is True).
Example:
if WifiService.is_connected():
print("WiFi is connected")
WifiService.get_current_ssid(network_module=None)
Get the SSID of the currently connected network.
Parameters:
- network_module - Network module for dependency injection (testing)
Returns:
- str or None - Current SSID if connected, None otherwise
Example:
ssid = WifiService.get_current_ssid()
if ssid:
print(f"Connected to: {ssid}")
Scanning Functions
WifiService.scan_networks(network_module=None)
Scan for available WiFi networks.
Parameters:
- network_module - Network module for dependency injection (testing)
Returns:
- list - List of SSID strings found
Behavior:
- Manages wifi_busy flag automatically
- Returns empty list if WiFi is already busy
- Filters out empty SSIDs and invalid lengths
- Returns mock data on desktop
Example:
networks = WifiService.scan_networks()
for ssid in networks:
print(f"Found: {ssid}")
WifiService.is_busy()
Check if WiFi operations are currently in progress.
Returns:
- bool - True if WiFi is busy, False if available
Example:
if not WifiService.is_busy():
networks = WifiService.scan_networks()
Credential Management
WifiService.save_network(ssid, password, hidden=False)
Save a new WiFi network credential.
Parameters:
- ssid (str) - Network SSID
- password (str) - Network password
- hidden (bool) - Whether this is a hidden network (default: False)
Behavior:
- Saves to SharedPreferences (com.micropythonos.system.wifiservice)
- Updates class-level cache
- Hidden networks are always tried during auto-connect
Example:
# Save regular network
WifiService.save_network("HomeWiFi", "password123")
# Save hidden network
WifiService.save_network("SecretNetwork", "hidden_pass", hidden=True)
WifiService.forget_network(ssid)
Remove a saved WiFi network.
Parameters:
- ssid (str) - Network SSID to forget
Returns:
- bool - True if network was found and removed, False otherwise
Example:
if WifiService.forget_network("OldNetwork"):
print("Network forgotten")
else:
print("Network not found")
WifiService.get_saved_networks()
Get list of saved network SSIDs.
Returns:
- list - List of saved SSID strings
Example:
saved = WifiService.get_saved_networks()
print(f"Saved networks: {saved}")
WifiService.get_network_password(ssid)
Get the saved password for a network.
Parameters:
- ssid (str) - Network SSID
Returns:
- str or None - Password if found, None otherwise
Example:
password = WifiService.get_network_password("HomeWiFi")
if password:
print("Password found")
ADC2 Compatibility
WifiService.temporarily_disable(network_module=None)
Temporarily disable WiFi for operations that require it (e.g., ESP32-S3 ADC2).
Parameters:
- network_module - Network module for dependency injection (testing)
Returns:
- bool - True if WiFi was connected before disabling, False otherwise
Raises:
- RuntimeError - If WiFi operations are already in progress
Example:
try:
was_connected = WifiService.temporarily_disable()
# Do ADC2 operations here
finally:
WifiService.temporarily_enable(was_connected)
WifiService.temporarily_enable(was_connected, network_module=None)
Re-enable WiFi after temporary disable operation.
Parameters:
- was_connected (bool) - Return value from temporarily_disable()
- network_module - Network module for dependency injection (testing)
Behavior:
- Clears wifi_busy flag
- Starts auto-connect thread if WiFi was previously connected
Example:
WifiService.temporarily_enable(was_connected)
Desktop Mode
On desktop (Linux/macOS), WifiService provides simulated behavior for testing:
| Method | Desktop Behavior |
|---|---|
is_connected() |
Always returns True |
scan_networks() |
Returns mock SSIDs: "Home WiFi", "Pretty Fly for a Wi Fi", etc. |
attempt_connecting() |
Simulates 2-second connection delay, always succeeds |
get_current_ssid() |
Returns simulated connected SSID |
disconnect() |
Prints message, no-op |
This allows WiFi-related apps to be tested on desktop without actual WiFi hardware.
Credential Storage
Network credentials are stored using SharedPreferences:
- Preference name:
com.micropythonos.system.wifiservice - Key:
access_points - Format: Dictionary
{ssid: {password: "...", hidden: bool}}
Storage location: data/com.micropythonos.system.wifiservice/prefs.json
{
"access_points": {
"HomeWiFi": {"password": "mypassword"},
"HiddenNetwork": {"password": "secret", "hidden": true}
}
}
Troubleshooting
WiFi Won't Connect
Symptom: attempt_connecting() returns False
Possible causes: 1. Wrong password 2. Network out of range 3. WiFi hardware issue
Solution:
# Check if WiFi is busy
if WifiService.is_busy():
print("WiFi is busy with another operation")
return
# Try connecting with verbose output
success = WifiService.attempt_connecting("SSID", "password")
# Check console for "WifiService:" messages
Scan Returns Empty List
Symptom: scan_networks() returns []
Possible causes: 1. WiFi is busy (connecting, scanning) 2. No networks in range 3. WiFi hardware not initialized
Solution:
# Check if busy first
if WifiService.is_busy():
print("WiFi is busy, try again later")
else:
networks = WifiService.scan_networks()
if not networks:
print("No networks found in range")
Auto-Connect Not Working
Symptom: Device doesn't connect to saved networks on boot
Possible causes: 1. No networks saved 2. Saved networks not in range 3. WiFi busy flag stuck
Solution:
# Check saved networks
saved = WifiService.get_saved_networks()
print(f"Saved networks: {saved}")
# Check busy state
print(f"WiFi busy: {WifiService.is_busy()}")
# Manually trigger auto-connect
import _thread
_thread.start_new_thread(WifiService.auto_connect, ())
ADC2 RuntimeError
Symptom: RuntimeError: Cannot disable WiFi: WifiService is already busy
Cause: Trying to disable WiFi while scanning or connecting
Solution:
# Wait for WiFi to be available
import time
while WifiService.is_busy():
time.sleep(0.1)
# Now safe to disable
was_connected = WifiService.temporarily_disable()
Hidden Network Not Connecting
Symptom: Hidden network saved but never connects
Cause: Network not marked as hidden when saved
Solution:
# Save with hidden=True
WifiService.save_network("HiddenSSID", "password", hidden=True)
Implementation Details
Location: MicroPythonOS/internal_filesystem/lib/mpos/net/wifi_service.py
Pattern: Static class with class-level state
Key features:
- wifi_busy - Class-level lock for concurrent access
- access_points - Cached dictionary of saved networks
- _desktop_connected_ssid - Simulated SSID for desktop mode
Dependencies:
- network module (MicroPython, not available on desktop)
- mpos.config.SharedPreferences - Credential storage
- mpos.time - NTP time sync after connection
See Also
- ConnectivityManager - Network connectivity monitoring
- DownloadManager - HTTP downloads
- SharedPreferences - Persistent storage