Files
spore/docs/ConfigurationManagement.md
2025-10-19 13:48:13 +02:00

338 lines
10 KiB
Markdown

# SPORE Configuration Management
## Overview
SPORE implements a persistent configuration system that manages device settings across reboots and provides runtime reconfiguration capabilities. The system uses LittleFS for persistent storage and provides both programmatic and HTTP API access to configuration parameters.
## Configuration Architecture
### Core Components
- **`Config` Class**: Central configuration management
- **LittleFS Storage**: Persistent file-based storage (`/config.json`)
- **Default Constants**: Single source of truth for all default values
- **Runtime Updates**: Live configuration changes via HTTP API
- **Automatic Persistence**: Configuration changes are automatically saved
### Configuration Categories
The configuration system manages several categories of settings:
| Category | Description | Examples |
|----------|-------------|----------|
| **WiFi Configuration** | Network connection settings | SSID, password, timeouts |
| **Network Configuration** | Network service settings | UDP port, API server port |
| **Cluster Configuration** | Cluster management settings | Discovery intervals, heartbeat timing |
| **Node Status Thresholds** | Health monitoring thresholds | Active/inactive/dead timeouts |
| **System Configuration** | Core system settings | Restart delay, JSON document size |
| **Memory Management** | Resource management settings | Memory thresholds, HTTP request limits |
## Configuration Lifecycle
### 1. Boot Process
```mermaid
graph TD
A[System Boot] --> B[Initialize LittleFS]
B --> C{Config File Exists?}
C -->|Yes| D[Load from File]
C -->|No| E[Use Defaults]
D --> F[Apply Configuration]
E --> G[Save Defaults to File]
G --> F
F --> H[Start Services]
```
**Boot Sequence:**
1. **LittleFS Initialization**: Mount the filesystem for persistent storage
2. **Configuration Loading**: Attempt to load `/config.json`
3. **Fallback to Defaults**: If no config file exists, use hardcoded defaults
4. **Default Persistence**: Save default configuration to file for future boots
5. **Service Initialization**: Apply configuration to all system services
### 2. Runtime Configuration
```mermaid
graph TD
A[HTTP API Request] --> B[Validate Parameters]
B --> C[Update Config Object]
C --> D[Save to File]
D --> E{Requires Restart?}
E -->|Yes| F[Schedule Restart]
E -->|No| G[Apply Changes]
F --> H[Send Response]
G --> H
```
**Runtime Update Process:**
1. **API Request**: Configuration change via HTTP API
2. **Parameter Validation**: Validate input parameters
3. **Memory Update**: Update configuration object in memory
4. **Persistent Save**: Save changes to `/config.json`
5. **Service Notification**: Notify affected services of changes
6. **Restart if Needed**: Restart system for certain configuration changes
## Configuration File Format
### JSON Structure
The configuration is stored as a JSON file with the following structure:
```json
{
"wifi": {
"ssid": "MyNetwork",
"password": "mypassword",
"connect_timeout_ms": 15000,
"retry_delay_ms": 500
},
"network": {
"udp_port": 4210,
"api_server_port": 80
},
"cluster": {
"heartbeat_interval_ms": 5000,
"cluster_listen_interval_ms": 10,
"status_update_interval_ms": 1000
},
"thresholds": {
"node_active_threshold_ms": 10000,
"node_inactive_threshold_ms": 60000,
"node_dead_threshold_ms": 120000
},
"system": {
"restart_delay_ms": 10,
"json_doc_size": 1024
},
"memory": {
"low_memory_threshold_bytes": 10000,
"critical_memory_threshold_bytes": 5000,
"max_concurrent_http_requests": 3
},
"_meta": {
"version": "1.0",
"saved_at": 1234567890
}
}
```
### Metadata Fields
- **`version`**: Configuration schema version for future compatibility
- **`saved_at`**: Timestamp when configuration was saved (millis())
## Default Configuration Constants
All default values are defined as `constexpr` constants in the `Config` class header:
```cpp
// Default Configuration Constants
static constexpr const char* DEFAULT_WIFI_SSID = "shroud";
static constexpr const char* DEFAULT_WIFI_PASSWORD = "th3r31sn0sp00n";
static constexpr uint16_t DEFAULT_UDP_PORT = 4210;
static constexpr uint16_t DEFAULT_API_SERVER_PORT = 80;
// ... additional constants
```
### Benefits of Constants
- **Single Source of Truth**: All defaults defined once
- **Type Safety**: Compile-time type checking
- **Maintainability**: Easy to update default values
- **Consistency**: Same defaults used in `setDefaults()` and `loadFromFile()`
## Configuration Methods
### Core Methods
| Method | Purpose | Parameters |
|--------|---------|------------|
| `setDefaults()` | Initialize with default values | None |
| `loadFromFile()` | Load configuration from persistent storage | `filename` (optional) |
| `saveToFile()` | Save configuration to persistent storage | `filename` (optional) |
### Loading Process
```cpp
bool Config::loadFromFile(const String& filename) {
// 1. Initialize LittleFS
if (!LittleFS.begin()) {
LOG_ERROR("Config", "LittleFS not initialized");
return false;
}
// 2. Check file existence
if (!LittleFS.exists(filename)) {
LOG_DEBUG("Config", "Config file does not exist");
return false;
}
// 3. Parse JSON with fallback defaults
wifi_ssid = doc["wifi"]["ssid"] | DEFAULT_WIFI_SSID;
wifi_password = doc["wifi"]["password"] | DEFAULT_WIFI_PASSWORD;
// ... additional fields
return true;
}
```
### Saving Process
```cpp
bool Config::saveToFile(const String& filename) {
// 1. Create JSON document
JsonDocument doc;
// 2. Serialize all configuration fields
doc["wifi"]["ssid"] = wifi_ssid;
doc["wifi"]["password"] = wifi_password;
// ... additional fields
// 3. Add metadata
doc["_meta"]["version"] = "1.0";
doc["_meta"]["saved_at"] = millis();
// 4. Write to file
size_t bytesWritten = serializeJson(doc, file);
return bytesWritten > 0;
}
```
## Error Handling
### Common Error Scenarios
| Scenario | Error Handling | Recovery |
|----------|----------------|----------|
| **LittleFS Init Failure** | Log warning, use defaults | Continue with default configuration |
| **File Not Found** | Log debug message, return false | Caller handles fallback to defaults |
| **JSON Parse Error** | Log error, return false | Caller handles fallback to defaults |
| **Write Failure** | Log error, return false | Configuration not persisted |
| **Memory Allocation Failure** | Log error, return false | Operation aborted |
### Logging Levels
- **ERROR**: Critical failures that prevent operation
- **WARN**: Non-critical issues that affect functionality
- **INFO**: Normal operation events
- **DEBUG**: Detailed diagnostic information
## Configuration Validation
### Input Validation
- **Required Fields**: SSID and password are mandatory for WiFi configuration
- **Range Validation**: Numeric values are validated against reasonable ranges
- **Type Validation**: JSON parsing ensures correct data types
- **Length Limits**: String fields have maximum length constraints
### Default Value Fallback
The system uses the `|` operator for safe fallback to defaults:
```cpp
// Safe loading with fallback
wifi_ssid = doc["wifi"]["ssid"] | DEFAULT_WIFI_SSID;
udp_port = doc["network"]["udp_port"] | DEFAULT_UDP_PORT;
```
This ensures that:
- Missing fields use default values
- Invalid values are replaced with defaults
- System remains functional with partial configuration
## Performance Considerations
### Memory Usage
- **Configuration Object**: ~200 bytes in RAM
- **JSON Document**: ~1KB during parsing/saving
- **LittleFS Overhead**: ~2-4KB for filesystem
### Storage Requirements
- **Config File**: ~500-800 bytes on disk
- **LittleFS Minimum**: ~64KB partition size
- **Available Space**: Depends on flash size (1MB+ recommended)
### Processing Overhead
- **Load Time**: ~10-50ms for JSON parsing
- **Save Time**: ~20-100ms for JSON serialization
- **File I/O**: Minimal impact on system performance
## Security Considerations
### Current Implementation
- **Local Storage Only**: Configuration stored on device filesystem
- **No Encryption**: Plain text storage (LAN-only access assumed)
- **Access Control**: No authentication for configuration changes
### Future Enhancements
- **Configuration Encryption**: Encrypt sensitive fields (passwords)
- **Access Control**: Authentication for configuration changes
- **Audit Logging**: Track configuration modifications
- **Backup/Restore**: Configuration backup and restore capabilities
## Troubleshooting
### Common Issues
1. **Configuration Not Persisting**
- Check LittleFS initialization
- Verify file write permissions
- Monitor available flash space
2. **Default Values Not Applied**
- Verify constants are properly defined
- Check JSON parsing errors
- Ensure fallback logic is working
3. **Configuration Corruption**
- Delete `/config.json` to reset to defaults
- Check for JSON syntax errors
- Verify file system integrity
### Debug Commands
```bash
# Check configuration status
curl -s http://192.168.1.100/api/network/status | jq '.'
# View current WiFi settings
curl -s http://192.168.1.100/api/network/status | jq '.wifi'
# Test configuration save
curl -X POST http://192.168.1.100/api/network/wifi/config \
-d "ssid=TestNetwork&password=testpass"
```
## Best Practices
### Configuration Management
1. **Use Constants**: Always define defaults as constants
2. **Validate Input**: Check all configuration parameters
3. **Handle Errors**: Implement proper error handling
4. **Log Changes**: Log configuration modifications
5. **Test Fallbacks**: Ensure default fallbacks work correctly
### Development Guidelines
1. **Single Source**: Define each default value only once
2. **Type Safety**: Use appropriate data types
3. **Documentation**: Document all configuration parameters
4. **Versioning**: Include version metadata in config files
5. **Backward Compatibility**: Handle old configuration formats
## Related Documentation
- **[WiFi Configuration Process](./WiFiConfiguration.md)** - Detailed WiFi setup workflow
- **[API Reference](./API.md)** - HTTP API for configuration management
- **[Architecture Overview](./Architecture.md)** - System architecture and components
- **[OpenAPI Specification](../api/)** - Machine-readable API specification