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

10 KiB

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

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

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:

{
  "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:

// 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

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

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:

// 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

# 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