479 lines
12 KiB
Markdown
479 lines
12 KiB
Markdown
# SPORE WiFi Configuration Process
|
|
|
|
## Overview
|
|
|
|
SPORE implements a WiFi configuration system that handles initial setup, runtime reconfiguration, and automatic fallback mechanisms. The system supports both Station (STA) and Access Point (AP) modes with seamless switching between them.
|
|
|
|
## WiFi Configuration Architecture
|
|
|
|
### Core Components
|
|
|
|
- **`NetworkManager`**: Handles WiFi operations and configuration
|
|
- **`NetworkService`**: Provides HTTP API endpoints for WiFi management
|
|
- **`Config`**: Stores WiFi credentials and connection parameters
|
|
- **LittleFS**: Persistent storage for WiFi configuration
|
|
- **ESP8266 WiFi Library**: Low-level WiFi operations
|
|
|
|
### Configuration Parameters
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `wifi_ssid` | String | "shroud" | Network SSID for connection |
|
|
| `wifi_password` | String | "th3r31sn0sp00n" | Network password |
|
|
| `wifi_connect_timeout_ms` | uint32_t | 15000 | Connection timeout (15 seconds) |
|
|
| `wifi_retry_delay_ms` | uint32_t | 500 | Delay between connection attempts |
|
|
|
|
## WiFi Configuration Lifecycle
|
|
|
|
### 1. Boot Process
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[System Boot] --> B[Initialize LittleFS]
|
|
B --> C[Load Configuration]
|
|
C --> D[Initialize WiFi Mode]
|
|
D --> E[Set Hostname from MAC]
|
|
E --> F[Attempt STA Connection]
|
|
F --> G{Connection Successful?}
|
|
G -->|Yes| H[STA Mode Active]
|
|
G -->|No| I[Switch to AP Mode]
|
|
I --> J[Create Access Point]
|
|
J --> K[AP Mode Active]
|
|
H --> L[Start UDP Services]
|
|
K --> L
|
|
L --> M[Initialize Node Context]
|
|
M --> N[Start Cluster Services]
|
|
```
|
|
|
|
**Detailed Boot Sequence:**
|
|
|
|
1. **LittleFS Initialization**
|
|
```cpp
|
|
if (!LittleFS.begin()) {
|
|
LOG_WARN("Config", "Failed to initialize LittleFS, using defaults");
|
|
setDefaults();
|
|
return;
|
|
}
|
|
```
|
|
|
|
2. **Configuration Loading**
|
|
- Load WiFi credentials from `/config.json`
|
|
- Fall back to defaults if file doesn't exist
|
|
- Validate configuration parameters
|
|
|
|
3. **WiFi Mode Initialization**
|
|
```cpp
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.begin(ctx.config.wifi_ssid.c_str(), ctx.config.wifi_password.c_str());
|
|
```
|
|
|
|
4. **Hostname Generation**
|
|
```cpp
|
|
void NetworkManager::setHostnameFromMac() {
|
|
uint8_t mac[6];
|
|
WiFi.macAddress(mac);
|
|
char buf[32];
|
|
sprintf(buf, "esp-%02X%02X%02X%02X%02X%02X",
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
WiFi.hostname(buf);
|
|
ctx.hostname = String(buf);
|
|
}
|
|
```
|
|
|
|
5. **Connection Attempt**
|
|
```cpp
|
|
unsigned long startAttemptTime = millis();
|
|
while (WiFi.status() != WL_CONNECTED &&
|
|
millis() - startAttemptTime < ctx.config.wifi_connect_timeout_ms) {
|
|
delay(ctx.config.wifi_retry_delay_ms);
|
|
}
|
|
```
|
|
|
|
6. **Fallback to AP Mode**
|
|
```cpp
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
LOG_WARN("WiFi", "Failed to connect to AP. Creating AP...");
|
|
WiFi.mode(WIFI_AP);
|
|
WiFi.softAP(ctx.config.wifi_ssid.c_str(), ctx.config.wifi_password.c_str());
|
|
}
|
|
```
|
|
|
|
### 2. Runtime Reconfiguration
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[HTTP API Request] --> B[Validate Parameters]
|
|
B --> C[Update Config Object]
|
|
C --> D[Save to Persistent Storage]
|
|
D --> E[Send Response to Client]
|
|
E --> F[Schedule Node Restart]
|
|
F --> G[Node Restarts]
|
|
G --> H[Apply New Configuration]
|
|
H --> I[Attempt New Connection]
|
|
```
|
|
|
|
**Runtime Reconfiguration Process:**
|
|
|
|
1. **API Request Validation**
|
|
```cpp
|
|
if (!request->hasParam("ssid", true) || !request->hasParam("password", true)) {
|
|
request->send(400, "application/json", "{\"error\": \"Missing required parameters\"}");
|
|
return;
|
|
}
|
|
```
|
|
|
|
2. **Configuration Update**
|
|
```cpp
|
|
void NetworkManager::setWiFiConfig(const String& ssid, const String& password,
|
|
uint32_t connect_timeout_ms, uint32_t retry_delay_ms) {
|
|
ctx.config.wifi_ssid = ssid;
|
|
ctx.config.wifi_password = password;
|
|
ctx.config.wifi_connect_timeout_ms = connect_timeout_ms;
|
|
ctx.config.wifi_retry_delay_ms = retry_delay_ms;
|
|
}
|
|
```
|
|
|
|
3. **Persistent Storage**
|
|
```cpp
|
|
bool configSaved = networkManager.saveConfig();
|
|
if (!configSaved) {
|
|
LOG_WARN("NetworkService", "Failed to save WiFi configuration to persistent storage");
|
|
}
|
|
```
|
|
|
|
4. **Restart Scheduling**
|
|
```cpp
|
|
request->onDisconnect([this]() {
|
|
LOG_INFO("NetworkService", "Restarting node to apply WiFi configuration...");
|
|
delay(100); // Give time for response to be sent
|
|
networkManager.restartNode();
|
|
});
|
|
```
|
|
|
|
## WiFi Modes
|
|
|
|
### Station Mode (STA)
|
|
|
|
**Purpose**: Connect to existing WiFi network as a client
|
|
|
|
**Configuration**:
|
|
- SSID and password required
|
|
- Automatic IP assignment via DHCP
|
|
- Hostname set from MAC address
|
|
- UDP services on configured port
|
|
|
|
**Connection Process**:
|
|
1. Set WiFi mode to STA
|
|
2. Begin connection with credentials
|
|
3. Wait for connection with timeout
|
|
4. Set hostname and start services
|
|
|
|
### Access Point Mode (AP)
|
|
|
|
**Purpose**: Create WiFi hotspot when STA connection fails
|
|
|
|
**Configuration**:
|
|
- Uses configured SSID/password for AP
|
|
- Fixed IP address (usually 192.168.4.1)
|
|
- Allows other devices to connect
|
|
- Maintains cluster functionality
|
|
|
|
**AP Creation Process**:
|
|
1. Switch WiFi mode to AP
|
|
2. Create soft access point
|
|
3. Set AP IP address
|
|
4. Start services on AP IP
|
|
|
|
## HTTP API Endpoints
|
|
|
|
### Network Status
|
|
|
|
#### GET `/api/network/status`
|
|
|
|
Returns comprehensive WiFi and network status information.
|
|
|
|
**Response Fields**:
|
|
```json
|
|
{
|
|
"wifi": {
|
|
"connected": true,
|
|
"mode": "STA",
|
|
"ssid": "MyNetwork",
|
|
"ip": "192.168.1.100",
|
|
"mac": "AA:BB:CC:DD:EE:FF",
|
|
"hostname": "esp-AABBCCDDEEFF",
|
|
"rssi": -45,
|
|
"ap_ip": "192.168.4.1",
|
|
"ap_mac": "AA:BB:CC:DD:EE:FF",
|
|
"stations_connected": 0
|
|
}
|
|
}
|
|
```
|
|
|
|
### WiFi Scanning
|
|
|
|
#### GET `/api/network/wifi/scan`
|
|
|
|
Returns list of available WiFi networks from last scan.
|
|
|
|
**Response Fields**:
|
|
```json
|
|
{
|
|
"access_points": [
|
|
{
|
|
"ssid": "MyNetwork",
|
|
"rssi": -45,
|
|
"channel": 6,
|
|
"encryption_type": 4,
|
|
"hidden": false,
|
|
"bssid": "AA:BB:CC:DD:EE:FF"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### POST `/api/network/wifi/scan`
|
|
|
|
Initiates a new WiFi network scan.
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"status": "scanning",
|
|
"message": "WiFi scan started"
|
|
}
|
|
```
|
|
|
|
### WiFi Configuration
|
|
|
|
#### POST `/api/network/wifi/config`
|
|
|
|
Configures WiFi connection with new credentials.
|
|
|
|
**Parameters**:
|
|
- `ssid` (required): Network SSID
|
|
- `password` (required): Network password
|
|
- `connect_timeout_ms` (optional): Connection timeout (default: 10000)
|
|
- `retry_delay_ms` (optional): Retry delay (default: 500)
|
|
|
|
**Request Example**:
|
|
```bash
|
|
curl -X POST http://192.168.1.100/api/network/wifi/config \
|
|
-d "ssid=MyNewNetwork&password=newpassword&connect_timeout_ms=15000"
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "WiFi configuration updated and saved",
|
|
"config_saved": true,
|
|
"restarting": true
|
|
}
|
|
```
|
|
|
|
## WiFi Scanning Process
|
|
|
|
### Scanning Implementation
|
|
|
|
```cpp
|
|
void NetworkManager::scanWifi() {
|
|
if (!isScanning) {
|
|
isScanning = true;
|
|
LOG_INFO("WiFi", "Starting WiFi scan...");
|
|
WiFi.scanNetworksAsync([this](int networksFound) {
|
|
LOG_INFO("WiFi", "Scan completed, found " + String(networksFound) + " networks");
|
|
this->processAccessPoints();
|
|
this->isScanning = false;
|
|
}, true);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Access Point Processing
|
|
|
|
```cpp
|
|
void NetworkManager::processAccessPoints() {
|
|
int numNetworks = WiFi.scanComplete();
|
|
if (numNetworks <= 0) return;
|
|
|
|
accessPoints.clear();
|
|
for (int i = 0; i < numNetworks; i++) {
|
|
AccessPoint ap;
|
|
ap.ssid = WiFi.SSID(i);
|
|
ap.rssi = WiFi.RSSI(i);
|
|
ap.encryptionType = WiFi.encryptionType(i);
|
|
ap.channel = WiFi.channel(i);
|
|
ap.isHidden = ap.ssid.length() == 0;
|
|
|
|
uint8_t* newBssid = new uint8_t[6];
|
|
memcpy(newBssid, WiFi.BSSID(i), 6);
|
|
ap.bssid = newBssid;
|
|
|
|
accessPoints.push_back(ap);
|
|
}
|
|
WiFi.scanDelete();
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Connection Failures
|
|
|
|
| Error Type | Handling | Recovery |
|
|
|------------|----------|----------|
|
|
| **Invalid Credentials** | Log error, switch to AP mode | Manual reconfiguration via API |
|
|
| **Network Unavailable** | Log warning, switch to AP mode | Automatic retry on next boot |
|
|
| **Timeout** | Log timeout, switch to AP mode | Increase timeout or check network |
|
|
| **Hardware Failure** | Log error, continue in AP mode | Hardware replacement required |
|
|
|
|
### API Error Responses
|
|
|
|
```json
|
|
{
|
|
"error": "Missing required parameters",
|
|
"status": "error"
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"error": "Failed to save configuration",
|
|
"status": "error",
|
|
"config_saved": false
|
|
}
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Current Implementation
|
|
|
|
- **Plain Text Storage**: WiFi passwords stored unencrypted
|
|
- **Local Network Only**: No internet exposure
|
|
- **No Authentication**: API access without authentication
|
|
- **MAC-based Hostnames**: Predictable hostname generation
|
|
|
|
### Security Best Practices
|
|
|
|
1. **Network Isolation**: Keep SPORE devices on isolated network
|
|
2. **Strong Passwords**: Use complex WiFi passwords
|
|
3. **Regular Updates**: Keep firmware updated
|
|
4. **Access Control**: Implement network-level access control
|
|
|
|
### Future Security Enhancements
|
|
|
|
- **Password Encryption**: Encrypt stored WiFi credentials
|
|
- **API Authentication**: Add authentication to configuration API
|
|
- **Certificate-based Security**: Implement TLS/SSL
|
|
- **Access Control Lists**: Role-based configuration access
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **WiFi Connection Fails**
|
|
- Check SSID and password
|
|
- Verify network availability
|
|
- Check signal strength
|
|
- Increase connection timeout
|
|
|
|
2. **Configuration Not Persisting**
|
|
- Check LittleFS initialization
|
|
- Verify file write permissions
|
|
- Monitor available flash space
|
|
|
|
3. **AP Mode Not Working**
|
|
- Check AP credentials
|
|
- Verify IP address assignment
|
|
- Check for IP conflicts
|
|
|
|
4. **Scan Not Finding Networks**
|
|
- Wait for scan completion
|
|
- Check WiFi hardware
|
|
- Verify scan permissions
|
|
|
|
### Debug Commands
|
|
|
|
```bash
|
|
# Check WiFi status
|
|
curl -s http://192.168.1.100/api/network/status | jq '.wifi'
|
|
|
|
# Scan for networks
|
|
curl -X POST http://192.168.1.100/api/network/wifi/scan
|
|
|
|
# View scan results
|
|
curl -s http://192.168.1.100/api/network/wifi/scan | jq '.'
|
|
|
|
# Test configuration
|
|
curl -X POST http://192.168.1.100/api/network/wifi/config \
|
|
-d "ssid=TestNetwork&password=testpass"
|
|
```
|
|
|
|
### Log Analysis
|
|
|
|
**Successful Connection**:
|
|
```
|
|
[INFO] WiFi: Connected to AP, IP: 192.168.1.100
|
|
[INFO] WiFi: Hostname set to: esp-AABBCCDDEEFF
|
|
[INFO] WiFi: UDP listening on port 4210
|
|
```
|
|
|
|
**Connection Failure**:
|
|
```
|
|
[WARN] WiFi: Failed to connect to AP. Creating AP...
|
|
[INFO] WiFi: AP created, IP: 192.168.4.1
|
|
```
|
|
|
|
**Configuration Update**:
|
|
```
|
|
[INFO] NetworkService: Restarting node to apply WiFi configuration...
|
|
[INFO] WiFi: Connecting to AP...
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
### Connection Time
|
|
|
|
- **STA Connection**: 5-15 seconds typical
|
|
- **AP Creation**: 1-3 seconds
|
|
- **Scan Duration**: 5-10 seconds
|
|
- **Configuration Save**: 100-500ms
|
|
|
|
### Memory Usage
|
|
|
|
- **WiFi Stack**: ~20-30KB RAM
|
|
- **Scan Results**: ~1KB per network
|
|
- **Configuration**: ~200 bytes
|
|
- **API Buffers**: ~2-4KB
|
|
|
|
### Network Overhead
|
|
|
|
- **Scan Packets**: Minimal impact
|
|
- **Configuration API**: ~500 bytes per request
|
|
- **Status Updates**: ~200 bytes per response
|
|
|
|
## Best Practices
|
|
|
|
### Configuration Management
|
|
|
|
1. **Use Strong Passwords**: Implement password complexity requirements
|
|
2. **Set Appropriate Timeouts**: Balance connection speed vs reliability
|
|
3. **Monitor Connection Quality**: Track RSSI and connection stability
|
|
4. **Implement Retry Logic**: Handle temporary network issues
|
|
5. **Log Configuration Changes**: Audit trail for troubleshooting
|
|
|
|
### Development Guidelines
|
|
|
|
1. **Handle All Error Cases**: Implement comprehensive error handling
|
|
2. **Provide Clear Feedback**: Inform users of connection status
|
|
3. **Optimize Scan Frequency**: Balance discovery vs performance
|
|
4. **Test Fallback Scenarios**: Ensure AP mode works correctly
|
|
5. **Document Configuration Options**: Clear parameter documentation
|
|
|
|
## Related Documentation
|
|
|
|
- **[Configuration Management](./ConfigurationManagement.md)** - Persistent configuration system
|
|
- **[API Reference](./API.md)** - Complete HTTP API documentation
|
|
- **[Architecture Overview](./Architecture.md)** - System architecture and components
|
|
- **[OpenAPI Specification](../api/)** - Machine-readable API specification
|