Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions docs/WIFI_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,9 @@ You should see output indicating the service is active and running.

### Accessing the WiFi Setup Interface

1. **If WiFi is NOT connected**: The Raspberry Pi will automatically create an access point
- Connect to the WiFi network: **LEDMatrix-Setup**
- Password: **ledmatrix123** (default)
- Open a web browser and navigate to: `http://192.168.4.1:5000`
1. **If WiFi is NOT connected**: The Raspberry Pi will automatically create an access point (after a 90-second grace period)
- Connect to the WiFi network: **LEDMatrix-Setup** (open network, no password required)
- Open a web browser and navigate to: `http://192.168.4.1:5000` or `http://192.168.4.1` (captive portal may redirect)
- Or use the IP address shown in the web interface

2. **If WiFi IS connected**: Access the web interface normally
Expand Down Expand Up @@ -92,7 +91,7 @@ The WiFi monitor daemon (`wifi_monitor_daemon.py`) runs as a background service
3. Automatically disables AP mode when WiFi or Ethernet connection is established
4. Logs all state changes for troubleshooting

**Note**: By default, `auto_enable_ap_mode` is `true`, meaning AP mode will automatically activate when both WiFi and Ethernet are disconnected. This ensures you can always configure the device even when it has no network connection.
**Note**: By default, `auto_enable_ap_mode` is `true`, meaning AP mode will automatically activate when both WiFi and Ethernet are disconnected. However, there's a 90-second grace period (3 consecutive checks at 30-second intervals) to prevent AP mode from enabling on transient network hiccups. This ensures you can always configure the device even when it has no network connection.

### WiFi Manager Module

Expand Down Expand Up @@ -125,13 +124,14 @@ WiFi settings are stored in `config/wifi_config.json`:

**Configuration Options:**
- `ap_ssid`: SSID for the access point (default: "LEDMatrix-Setup")
- `ap_password`: Password for the access point (default: "ledmatrix123")
- `ap_channel`: WiFi channel for AP mode (default: 7)
- `auto_enable_ap_mode`: Automatically enable AP mode when WiFi/Ethernet disconnect (default: `true`)
- When `true`: AP mode automatically enables when both WiFi and Ethernet are disconnected
- When `true`: AP mode automatically enables after a 90-second grace period when both WiFi and Ethernet are disconnected
- When `false`: AP mode must be manually enabled through the web interface
- `saved_networks`: List of saved WiFi network credentials

**Note**: The access point is configured as an open network (no password required) for ease of initial setup. This allows any device to connect without credentials.

### Access Point Configuration

The AP mode uses `hostapd` and `dnsmasq` for access point functionality:
Expand All @@ -141,6 +141,31 @@ The AP mode uses `hostapd` and `dnsmasq` for access point functionality:
- **Gateway**: 192.168.4.1
- **Channel**: 7 (configurable)

## Verification

### Running the WiFi Verification Script

Use the comprehensive verification script to check your WiFi setup:

```bash
cd /home/ledpi/LEDMatrix
./scripts/verify_wifi_setup.sh
```

This script checks:
- Required packages are installed
- WiFi monitor service is running
- Configuration files are valid
- WiFi permissions are configured
- WiFi interface is available
- WiFi radio status
- Current connection status
- AP mode status
- WiFi Manager module availability
- Web interface API accessibility

The script provides a summary with passed/warning/failed checks to help diagnose issues.

## Troubleshooting

### WiFi Monitor Service Not Starting
Expand Down Expand Up @@ -254,12 +279,12 @@ sudo systemctl restart ledmatrix-wifi-monitor

## Security Considerations

- **Default AP Password**: The default AP password is "ledmatrix123". Consider changing this in `config/wifi_config.json` for production use
- **Open AP Network**: The access point is configured as an open network (no password) for ease of initial setup. This allows any device within range to connect to the setup network. Consider your deployment environment when using this feature.
- **WiFi Credentials**: Saved WiFi credentials are stored in `config/wifi_config.json`. Ensure proper file permissions:
```bash
sudo chmod 600 config/wifi_config.json
```
- **Network Access**: When in AP mode, anyone within range can connect to the setup network. Use strong passwords for production deployments
- **Network Access**: When in AP mode, anyone within range can connect to the setup network. This is by design to allow easy initial configuration. For production deployments in secure environments, consider using the web interface when connected to WiFi instead.

## API Endpoints

Expand Down Expand Up @@ -291,11 +316,13 @@ The system supports multiple scanning methods:

AP mode configuration:

- Uses `hostapd` for WiFi access point functionality
- Uses `dnsmasq` for DHCP and DNS services
- Uses `hostapd` (preferred) or `nmcli hotspot` (fallback) for WiFi access point functionality
- Uses `dnsmasq` for DHCP and DNS services (hostapd mode only)
- Configures wlan0 interface in AP mode
- Provides DHCP range: 192.168.4.2-20
- Gateway IP: 192.168.4.1
- **Open network**: No password required (configures as open network for easy setup)
- Captive portal: DNS redirection for automatic browser redirects (hostapd mode only)

## Development

Expand Down
83 changes: 65 additions & 18 deletions scripts/utils/wifi_monitor_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,39 +58,69 @@ def run(self):
logger.info("WiFi Monitor Daemon started")
logger.info(f"Check interval: {self.check_interval} seconds")

# Log initial configuration
auto_enable = self.wifi_manager.config.get("auto_enable_ap_mode", True)
ap_ssid = self.wifi_manager.config.get("ap_ssid", "LEDMatrix-Setup")
logger.info(f"Configuration: auto_enable_ap_mode={auto_enable}, ap_ssid={ap_ssid}")

# Log initial status
initial_status = self.wifi_manager.get_wifi_status()
initial_ethernet = self.wifi_manager._is_ethernet_connected()
logger.info(f"Initial status: WiFi connected={initial_status.connected}, "
f"Ethernet connected={initial_ethernet}, AP active={initial_status.ap_mode_active}")
if initial_status.connected:
logger.info(f" WiFi SSID: {initial_status.ssid}, IP: {initial_status.ip_address}, Signal: {initial_status.signal}%")

while self.running:
try:
# Get current status before checking
status = self.wifi_manager.get_wifi_status()
ethernet_connected = self.wifi_manager._is_ethernet_connected()

# Check WiFi status and manage AP mode
state_changed = self.wifi_manager.check_and_manage_ap_mode()

# Get current status for logging
status = self.wifi_manager.get_wifi_status()
ethernet_connected = self.wifi_manager._is_ethernet_connected()
# Get updated status after check
updated_status = self.wifi_manager.get_wifi_status()
updated_ethernet = self.wifi_manager._is_ethernet_connected()

current_state = {
'connected': status.connected,
'ethernet_connected': ethernet_connected,
'ap_active': status.ap_mode_active,
'ssid': status.ssid
'connected': updated_status.connected,
'ethernet_connected': updated_ethernet,
'ap_active': updated_status.ap_mode_active,
'ssid': updated_status.ssid
}

# Log state changes
# Log state changes with detailed information
if current_state != self.last_state:
if status.connected:
logger.info(f"WiFi connected: {status.ssid} (IP: {status.ip_address})")
logger.info("=== State Change Detected ===")
if updated_status.connected:
logger.info(f"WiFi connected: {updated_status.ssid} (IP: {updated_status.ip_address}, Signal: {updated_status.signal}%)")
else:
logger.info("WiFi disconnected")
logger.info("WiFi disconnected (no active connection)")

if ethernet_connected:
if updated_ethernet:
logger.info("Ethernet connected")
else:
logger.debug("Ethernet disconnected")
logger.debug("Ethernet not connected")

if status.ap_mode_active:
logger.info("AP mode active")
if updated_status.ap_mode_active:
logger.info(f"AP mode ACTIVE - SSID: {ap_ssid} (IP: 192.168.4.1)")
else:
logger.debug("AP mode inactive")

if state_changed:
logger.info("AP mode state was changed by check_and_manage_ap_mode()")

logger.info("=============================")
self.last_state = current_state.copy()
else:
# Log periodic status (less verbose)
if updated_status.connected:
logger.debug(f"Status check: WiFi={updated_status.ssid} ({updated_status.signal}%), "
f"Ethernet={updated_ethernet}, AP={updated_status.ap_mode_active}")
else:
logger.debug(f"Status check: WiFi=disconnected, Ethernet={updated_ethernet}, AP={updated_status.ap_mode_active}")

# Sleep until next check
time.sleep(self.check_interval)
Expand All @@ -101,23 +131,40 @@ def run(self):
break
except Exception as e:
logger.error(f"Error in monitor loop: {e}", exc_info=True)
logger.error(f"Error details - type: {type(e).__name__}, args: {e.args}")
# Log current state for debugging
try:
error_status = self.wifi_manager.get_wifi_status()
logger.error(f"State at error: WiFi={error_status.connected}, AP={error_status.ap_mode_active}")
except Exception as state_error:
logger.error(f"Could not get state at error: {state_error}")
# Continue running even if there's an error
time.sleep(self.check_interval)

logger.info("WiFi Monitor Daemon stopped")

# Ensure AP mode is disabled on shutdown if WiFi or Ethernet is connected
logger.info("Performing cleanup on shutdown...")
try:
status = self.wifi_manager.get_wifi_status()
ethernet_connected = self.wifi_manager._is_ethernet_connected()
logger.info(f"Final status: WiFi={status.connected}, Ethernet={ethernet_connected}, AP={status.ap_mode_active}")

if (status.connected or ethernet_connected) and status.ap_mode_active:
if status.connected:
logger.info("Disabling AP mode on shutdown (WiFi is connected)")
logger.info(f"Disabling AP mode on shutdown (WiFi is connected to {status.ssid})")
elif ethernet_connected:
logger.info("Disabling AP mode on shutdown (Ethernet is connected)")
self.wifi_manager.disable_ap_mode()

success, message = self.wifi_manager.disable_ap_mode()
if success:
logger.info(f"AP mode disabled successfully: {message}")
else:
logger.warning(f"Failed to disable AP mode: {message}")
else:
logger.debug("AP mode cleanup not needed (not active or no network connection)")
except Exception as e:
logger.error(f"Error disabling AP mode on shutdown: {e}")
logger.error(f"Error during shutdown cleanup: {e}", exc_info=True)


def main():
Expand Down
Loading