Configuration Management
Configuration Management API
Section titled “Configuration Management API”Remote configuration endpoints for updating device settings and parameters without physical access.
Endpoints
Section titled “Endpoints”Get Configuration
Section titled “Get Configuration”GET /api/v1/device/config/{device_id}Update Configuration
Section titled “Update Configuration”PUT /api/v1/device/config/{device_id}Purpose
Section titled “Purpose”- Update device operation parameters remotely
- Modify sampling rates and data collection modes
- Adjust BCGMCU sensitivity and filtering
- Configure system behavior and intervals
Get Configuration Request
Section titled “Get Configuration Request”Headers
Section titled “Headers”Authorization: Bearer {device_token}Response (200 OK)
Section titled “Response (200 OK)”{ "device_id": "BCGMCU_001", "configuration": { "operation_mode": "streaming", "streaming_settings": { "rate_hz": 1, "data_fields": ["pulse", "breathing", "presence"], "quality_threshold": "good" }, "batch_settings": { "interval_seconds": 3600, "max_batch_size": 10000, "compression_enabled": true }, "bcgmcu_settings": { "sensitivity": "high", "filter_mode": "adaptive", "presence_timeout": 30, "calibration_mode": "auto" }, "system_settings": { "status_interval": 300, "wifi_power_save": false, "debug_logging": false } }, "applied_timestamp": "2025-01-27T10:30:00.000Z", "config_version": "v1.2.3"}Update Configuration Request
Section titled “Update Configuration Request”Headers
Section titled “Headers”Content-Type: application/jsonAuthorization: Bearer {device_token}Request Body
Section titled “Request Body”{ "device_id": "BCGMCU_001", "configuration": { "operation_mode": "hybrid", "streaming_settings": { "rate_hz": 2, "data_fields": ["pulse", "breathing", "presence", "accelerometer"], "quality_threshold": "fair" }, "batch_settings": { "interval_seconds": 1800, "max_batch_size": 5000, "compression_enabled": true }, "bcgmcu_settings": { "sensitivity": "medium", "filter_mode": "fixed", "presence_timeout": 60, "calibration_mode": "manual" }, "system_settings": { "status_interval": 180, "wifi_power_save": true, "debug_logging": true } }}Configuration Parameters
Section titled “Configuration Parameters”Operation Mode
Section titled “Operation Mode”| Mode | Description | Use Case |
|---|---|---|
| streaming | Real-time data transmission only | Continuous monitoring |
| batch | Periodic batch uploads only | Offline data collection |
| hybrid | Both streaming and batching | Comprehensive data capture |
Streaming Settings
Section titled “Streaming Settings”| Parameter | Type | Range | Description |
|---|---|---|---|
| rate_hz | integer | 0.1-10 | Transmission frequency in Hz |
| data_fields | array | predefined | Fields to include in stream |
| quality_threshold | string | poor/fair/good/excellent | Minimum signal quality |
Batch Settings
Section titled “Batch Settings”| Parameter | Type | Range | Description |
|---|---|---|---|
| interval_seconds | integer | 300-86400 | Time between batch uploads |
| max_batch_size | integer | 100-100000 | Maximum samples per batch |
| compression_enabled | boolean | true/false | Enable gzip compression |
BCGMCU Settings
Section titled “BCGMCU Settings”| Parameter | Type | Range | Description |
|---|---|---|---|
| sensitivity | string | low/medium/high | Sensor sensitivity level |
| filter_mode | string | fixed/adaptive | Signal filtering approach |
| presence_timeout | integer | 10-300 | Seconds before marking absent |
| calibration_mode | string | auto/manual | Calibration trigger mode |
System Settings
Section titled “System Settings”| Parameter | Type | Range | Description |
|---|---|---|---|
| status_interval | integer | 60-3600 | Status update frequency in seconds |
| wifi_power_save | boolean | true/false | Enable WiFi power saving |
| debug_logging | boolean | true/false | Enable detailed logging |
Response
Section titled “Response”Success Response (200 OK)
Section titled “Success Response (200 OK)”{ "config_status": "applied", "config_version": "v1.2.4", "restart_required": false, "validation_errors": [], "effective_timestamp": "2025-01-27T10:30:05.000Z"}Validation Error Response (400 Bad Request)
Section titled “Validation Error Response (400 Bad Request)”{ "config_status": "validation_failed", "validation_errors": [ { "field": "streaming_settings.rate_hz", "error": "Value 15 exceeds maximum of 10", "suggested_value": 10 }, { "field": "batch_settings.interval_seconds", "error": "Value 60 below minimum of 300", "suggested_value": 300 } ]}Implementation Example
Section titled “Implementation Example”ESP32 Configuration Client
Section titled “ESP32 Configuration Client”#include <HTTPClient.h>#include <ArduinoJson.h>#include <Preferences.h>
class ConfigurationManager {private: Preferences prefs; String configVersion; unsigned long lastConfigCheck = 0;
struct DeviceConfig { String operation_mode = "streaming"; float streaming_rate = 1.0; int batch_interval = 3600; String sensitivity = "medium"; int status_interval = 300; bool wifi_power_save = false; bool debug_logging = false; } config;
public: void initialize() { prefs.begin("config", false); loadStoredConfig(); }
void checkForUpdates() { // Check for configuration updates every 5 minutes if (millis() - lastConfigCheck < 300000) { return; } lastConfigCheck = millis();
// Only check if status indicated pending config if (!configUpdatePending) { return; }
fetchConfiguration(); }
void fetchConfiguration() { HTTPClient https; String url = API_BASE_URL + "/device/config/" + getDeviceId();
https.begin(url); https.addHeader("Authorization", "Bearer " + deviceToken);
int httpCode = https.GET();
if (httpCode == 200) { String response = https.getString(); parseConfiguration(response); } else { Serial.printf("Config fetch failed: %d\n", httpCode); }
https.end(); }
void parseConfiguration(String& response) { StaticJsonDocument<2048> doc; deserializeJson(doc, response);
String newVersion = doc["config_version"];
// Check if configuration changed if (newVersion != configVersion) { Serial.println("New configuration version: " + newVersion);
// Parse configuration sections JsonObject configObj = doc["configuration"];
config.operation_mode = configObj["operation_mode"].as<String>();
// Streaming settings if (configObj.containsKey("streaming_settings")) { JsonObject streaming = configObj["streaming_settings"]; config.streaming_rate = streaming["rate_hz"]; }
// Batch settings if (configObj.containsKey("batch_settings")) { JsonObject batch = configObj["batch_settings"]; config.batch_interval = batch["interval_seconds"]; }
// BCGMCU settings if (configObj.containsKey("bcgmcu_settings")) { JsonObject bcgmcu = configObj["bcgmcu_settings"]; config.sensitivity = bcgmcu["sensitivity"].as<String>(); }
// System settings if (configObj.containsKey("system_settings")) { JsonObject system = configObj["system_settings"]; config.status_interval = system["status_interval"]; config.wifi_power_save = system["wifi_power_save"]; config.debug_logging = system["debug_logging"]; }
// Apply new configuration applyConfiguration();
// Store configuration saveConfiguration();
configVersion = newVersion; configUpdatePending = false; } }
private: void applyConfiguration() { Serial.println("Applying new configuration:");
// Apply operation mode if (config.operation_mode == "streaming") { setOperationMode(MODE_STREAMING); } else if (config.operation_mode == "batch") { setOperationMode(MODE_BATCH); } else if (config.operation_mode == "hybrid") { setOperationMode(MODE_HYBRID); }
// Apply streaming rate setStreamingRate(config.streaming_rate);
// Apply batch interval setBatchInterval(config.batch_interval);
// Apply BCGMCU sensitivity bcgmcu.setSensitivity(config.sensitivity);
// Apply system settings setStatusInterval(config.status_interval);
if (config.wifi_power_save) { WiFi.setSleep(WIFI_PS_MIN_MODEM); } else { WiFi.setSleep(WIFI_PS_NONE); }
setDebugLogging(config.debug_logging);
Serial.println("Configuration applied successfully"); }
void saveConfiguration() { prefs.putString("op_mode", config.operation_mode); prefs.putFloat("stream_rate", config.streaming_rate); prefs.putInt("batch_int", config.batch_interval); prefs.putString("sensitivity", config.sensitivity); prefs.putInt("status_int", config.status_interval); prefs.putBool("wifi_save", config.wifi_power_save); prefs.putBool("debug_log", config.debug_logging); prefs.putString("version", configVersion); }
void loadStoredConfig() { config.operation_mode = prefs.getString("op_mode", "streaming"); config.streaming_rate = prefs.getFloat("stream_rate", 1.0); config.batch_interval = prefs.getInt("batch_int", 3600); config.sensitivity = prefs.getString("sensitivity", "medium"); config.status_interval = prefs.getInt("status_int", 300); config.wifi_power_save = prefs.getBool("wifi_save", false); config.debug_logging = prefs.getBool("debug_log", false); configVersion = prefs.getString("version", "v0.0.0");
// Apply stored configuration applyConfiguration(); }};Configuration Validation
Section titled “Configuration Validation”class ConfigValidator {public: struct ValidationResult { bool valid; std::vector<String> errors; };
ValidationResult validateConfig(JsonObject& config) { ValidationResult result; result.valid = true;
// Validate operation mode String mode = config["operation_mode"]; if (mode != "streaming" && mode != "batch" && mode != "hybrid") { result.errors.push_back("Invalid operation_mode: " + mode); result.valid = false; }
// Validate streaming settings if (config.containsKey("streaming_settings")) { JsonObject streaming = config["streaming_settings"];
float rate = streaming["rate_hz"]; if (rate < 0.1 || rate > 10.0) { result.errors.push_back("streaming_rate must be 0.1-10.0 Hz"); result.valid = false; } }
// Validate batch settings if (config.containsKey("batch_settings")) { JsonObject batch = config["batch_settings"];
int interval = batch["interval_seconds"]; if (interval < 300 || interval > 86400) { result.errors.push_back("batch_interval must be 300-86400 seconds"); result.valid = false; }
int maxSize = batch["max_batch_size"]; if (maxSize < 100 || maxSize > 100000) { result.errors.push_back("max_batch_size must be 100-100000"); result.valid = false; } }
// Validate BCGMCU settings if (config.containsKey("bcgmcu_settings")) { JsonObject bcgmcu = config["bcgmcu_settings"];
String sensitivity = bcgmcu["sensitivity"]; if (sensitivity != "low" && sensitivity != "medium" && sensitivity != "high") { result.errors.push_back("Invalid sensitivity: " + sensitivity); result.valid = false; } }
return result; }};Configuration Backup and Recovery
Section titled “Configuration Backup and Recovery”class ConfigBackup {private: static const int MAX_BACKUPS = 5;
public: void backupCurrentConfig() { // Create backup entry StaticJsonDocument<1024> backup; backup["timestamp"] = getCurrentTimestamp(); backup["version"] = configVersion; backup["config"] = getCurrentConfigJson();
// Store in SPIFFS String filename = "/config_backup_" + String(millis()) + ".json"; File file = SPIFFS.open(filename, "w"); serializeJson(backup, file); file.close();
// Clean old backups cleanupOldBackups(); }
void restoreLastKnownGood() { // Find most recent valid backup File root = SPIFFS.open("/"); File file = root.openNextFile();
String latestBackup; unsigned long latestTime = 0;
while (file) { String name = file.name(); if (name.startsWith("config_backup_")) { unsigned long time = name.substring(14).toInt(); if (time > latestTime) { latestTime = time; latestBackup = name; } } file = root.openNextFile(); }
if (latestBackup.length() > 0) { restoreFromBackup(latestBackup); } }
private: void cleanupOldBackups() { // Keep only MAX_BACKUPS most recent files std::vector<String> backups;
File root = SPIFFS.open("/"); File file = root.openNextFile();
while (file) { String name = file.name(); if (name.startsWith("config_backup_")) { backups.push_back(name); } file = root.openNextFile(); }
// Sort by timestamp (filename contains timestamp) std::sort(backups.begin(), backups.end());
// Remove oldest backups while (backups.size() > MAX_BACKUPS) { SPIFFS.remove(backups[0]); backups.erase(backups.begin()); } }};Best Practices
Section titled “Best Practices”- Configuration Versioning: Always track configuration versions
- Validation: Validate all parameters before applying
- Gradual Rollout: Test configurations on subset of devices
- Backup and Recovery: Maintain configuration backups
- Restart Minimal: Apply changes without restart when possible
- Error Handling: Gracefully handle invalid configurations
- Status Monitoring: Monitor device behavior after config changes
Configuration Scheduling
Section titled “Configuration Scheduling”class ConfigScheduler {public: void scheduleConfigUpdate(JsonObject& config, unsigned long delayMs) { ScheduledConfig scheduled; scheduled.config = config; scheduled.executeTime = millis() + delayMs; scheduled.applied = false;
scheduledConfigs.push_back(scheduled); }
void processScheduledConfigs() { for (auto& scheduled : scheduledConfigs) { if (!scheduled.applied && millis() >= scheduled.executeTime) { applyConfiguration(scheduled.config); scheduled.applied = true; } }
// Clean up applied configs scheduledConfigs.erase( std::remove_if(scheduledConfigs.begin(), scheduledConfigs.end(), [](const ScheduledConfig& s) { return s.applied; }), scheduledConfigs.end() ); }
private: struct ScheduledConfig { JsonObject config; unsigned long executeTime; bool applied; };
std::vector<ScheduledConfig> scheduledConfigs;};