Fixed MQTT and WS Routing - w/o SSL
This commit is contained in:
@@ -44,7 +44,7 @@ void ConfigManager::createDefaultBellConfig() {
|
||||
// Initialize default durations (90ms for all bells)
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bellConfig.durations[i] = 90;
|
||||
bellConfig.outputs[i] = i; // Direct mapping by default
|
||||
bellConfig.outputs[i] = i + 1; // 1-indexed mapping by default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ bool ConfigManager::begin() {
|
||||
|
||||
// Step 4: Load device configuration from SD card (firmware version only)
|
||||
if (!loadDeviceConfig()) {
|
||||
LOG_WARNING("ConfigManager: Could not load device config from SD card - using defaults");
|
||||
LOG_INFO("ConfigManager: Creating default device config file");
|
||||
saveDeviceConfig();
|
||||
}
|
||||
|
||||
// Step 5: Load update servers list
|
||||
@@ -78,12 +79,32 @@ bool ConfigManager::begin() {
|
||||
LOG_WARNING("ConfigManager: Could not load update servers - using fallback only");
|
||||
}
|
||||
|
||||
// Step 6: Load user-configurable settings from SD
|
||||
// Step 6: Load user-configurable settings from SD (and create if missing)
|
||||
loadFromSD();
|
||||
loadNetworkConfig(); // Load network configuration (hostname, static IP settings)
|
||||
loadBellDurations();
|
||||
loadClockConfig(); // Load clock configuration (C1/C2 outputs, pulse durations)
|
||||
loadClockState(); // Load physical clock state (hour, minute, position)
|
||||
|
||||
// Load network config, save defaults if not found
|
||||
if (!loadNetworkConfig()) {
|
||||
LOG_INFO("ConfigManager: Creating default network config file");
|
||||
saveNetworkConfig();
|
||||
}
|
||||
|
||||
// Load bell durations, save defaults if not found
|
||||
if (!loadBellDurations()) {
|
||||
LOG_INFO("ConfigManager: Creating default bell durations file");
|
||||
saveBellDurations();
|
||||
}
|
||||
|
||||
// Load clock config, save defaults if not found
|
||||
if (!loadClockConfig()) {
|
||||
LOG_INFO("ConfigManager: Creating default clock config file");
|
||||
saveClockConfig();
|
||||
}
|
||||
|
||||
// Load clock state, save defaults if not found
|
||||
if (!loadClockState()) {
|
||||
LOG_INFO("ConfigManager: Creating default clock state file");
|
||||
saveClockState();
|
||||
}
|
||||
|
||||
LOG_INFO("ConfigManager: Initialization complete - UID: %s, Hostname: %s",
|
||||
deviceConfig.deviceUID.c_str(), networkConfig.hostname.c_str());
|
||||
@@ -123,42 +144,35 @@ bool ConfigManager::loadDeviceIdentityFromNVS() {
|
||||
return false;
|
||||
}
|
||||
|
||||
deviceConfig.deviceUID = readNVSString(NVS_DEVICE_UID_KEY, "PV000000000000");
|
||||
deviceConfig.hwType = readNVSString(NVS_HW_TYPE_KEY, "BellSystems");
|
||||
deviceConfig.hwVersion = readNVSString(NVS_HW_VERSION_KEY, "0");
|
||||
// Read factory-set device identity from NVS (READ-ONLY)
|
||||
deviceConfig.deviceUID = readNVSString(NVS_DEVICE_UID_KEY, "");
|
||||
deviceConfig.hwType = readNVSString(NVS_HW_TYPE_KEY, "");
|
||||
deviceConfig.hwVersion = readNVSString(NVS_HW_VERSION_KEY, "");
|
||||
|
||||
LOG_INFO("ConfigManager: Device identity loaded from NVS - UID: %s, Type: %s, Version: %s",
|
||||
deviceConfig.deviceUID.c_str(),
|
||||
deviceConfig.hwType.c_str(),
|
||||
deviceConfig.hwVersion.c_str());
|
||||
// Validate that factory identity exists
|
||||
if (deviceConfig.deviceUID.isEmpty() || deviceConfig.hwType.isEmpty() || deviceConfig.hwVersion.isEmpty()) {
|
||||
LOG_ERROR("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_ERROR(" ⚠️ CRITICAL: DEVICE IDENTITY NOT FOUND IN NVS");
|
||||
LOG_ERROR(" ⚠️ This device has NOT been factory-programmed!");
|
||||
LOG_ERROR(" ⚠️ Please flash factory firmware to set device identity");
|
||||
LOG_ERROR("═══════════════════════════════════════════════════════════════════════════");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_INFO(" 🏭 FACTORY DEVICE IDENTITY LOADED FROM NVS (READ-ONLY)");
|
||||
LOG_INFO(" 🆔 Device UID: %s", deviceConfig.deviceUID.c_str());
|
||||
LOG_INFO(" 🔧 Hardware Type: %s", deviceConfig.hwType.c_str());
|
||||
LOG_INFO(" 📐 Hardware Version: %s", deviceConfig.hwVersion.c_str());
|
||||
LOG_INFO(" 🔒 These values are PERMANENT and cannot be changed by production firmware");
|
||||
LOG_INFO("═══════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigManager::saveDeviceIdentityToNVS() {
|
||||
if (nvsHandle == 0) {
|
||||
LOG_ERROR("ConfigManager: NVS not initialized, cannot save device identity");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
success &= writeNVSString(NVS_DEVICE_UID_KEY, deviceConfig.deviceUID);
|
||||
success &= writeNVSString(NVS_HW_TYPE_KEY, deviceConfig.hwType);
|
||||
success &= writeNVSString(NVS_HW_VERSION_KEY, deviceConfig.hwVersion);
|
||||
|
||||
if (success) {
|
||||
esp_err_t err = nvs_commit(nvsHandle);
|
||||
if (err != ESP_OK) {
|
||||
LOG_ERROR("ConfigManager: Failed to commit NVS changes: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
LOG_INFO("ConfigManager: Device identity saved to NVS");
|
||||
} else {
|
||||
LOG_ERROR("ConfigManager: Failed to save device identity to NVS");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
// REMOVED: saveDeviceIdentityToNVS() - Production firmware MUST NOT write device identity
|
||||
// Device identity (UID, hwType, hwVersion) is factory-set ONLY and stored in NVS by factory firmware
|
||||
// Production firmware reads these values once at boot and keeps them in RAM
|
||||
|
||||
String ConfigManager::readNVSString(const char* key, const String& defaultValue) {
|
||||
if (nvsHandle == 0) {
|
||||
@@ -195,21 +209,8 @@ String ConfigManager::readNVSString(const char* key, const String& defaultValue)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConfigManager::writeNVSString(const char* key, const String& value) {
|
||||
if (nvsHandle == 0) {
|
||||
LOG_ERROR("ConfigManager: NVS not initialized, cannot write key: %s", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t err = nvs_set_str(nvsHandle, key, value.c_str());
|
||||
if (err != ESP_OK) {
|
||||
LOG_ERROR("ConfigManager: Failed to write NVS key '%s': %s", key, esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG("ConfigManager: Written NVS key '%s': %s", key, value.c_str());
|
||||
return true;
|
||||
}
|
||||
// REMOVED: writeNVSString() - Production firmware MUST NOT write to NVS
|
||||
// All device identity is factory-set and read-only in production firmware
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// STANDARD SD CARD FUNCTIONALITY
|
||||
@@ -327,7 +328,7 @@ bool ConfigManager::loadBellDurations() {
|
||||
|
||||
File file = SD.open("/settings/relayTimings.json", FILE_READ);
|
||||
if (!file) {
|
||||
LOG_ERROR("ConfigManager: Settings file not found on SD. Using default bell durations.");
|
||||
LOG_WARNING("ConfigManager: Settings file not found on SD. Using default bell durations.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -681,8 +682,9 @@ void ConfigManager::updateTimeConfig(long gmtOffsetSec, int daylightOffsetSec) {
|
||||
gmtOffsetSec, daylightOffsetSec);
|
||||
}
|
||||
|
||||
void ConfigManager::updateNetworkConfig(bool useStaticIP, IPAddress ip, IPAddress gateway,
|
||||
void ConfigManager::updateNetworkConfig(const String& hostname, bool useStaticIP, IPAddress ip, IPAddress gateway,
|
||||
IPAddress subnet, IPAddress dns1, IPAddress dns2) {
|
||||
networkConfig.hostname = hostname;
|
||||
networkConfig.useStaticIP = useStaticIP;
|
||||
networkConfig.ip = ip;
|
||||
networkConfig.gateway = gateway;
|
||||
@@ -690,8 +692,8 @@ void ConfigManager::updateNetworkConfig(bool useStaticIP, IPAddress ip, IPAddres
|
||||
networkConfig.dns1 = dns1;
|
||||
networkConfig.dns2 = dns2;
|
||||
saveNetworkConfig(); // Save immediately to SD
|
||||
LOG_INFO("ConfigManager: NetworkConfig updated - Static IP: %s, IP: %s",
|
||||
useStaticIP ? "enabled" : "disabled", ip.toString().c_str());
|
||||
LOG_INFO("ConfigManager: NetworkConfig updated - Hostname: %s, Static IP: %s, IP: %s",
|
||||
hostname.c_str(), useStaticIP ? "enabled" : "disabled", ip.toString().c_str());
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
@@ -802,96 +804,28 @@ bool ConfigManager::saveNetworkConfig() {
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// FACTORY RESET IMPLEMENTATION
|
||||
// SETTINGS RESET IMPLEMENTATION
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
bool ConfigManager::factoryReset() {
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_WARNING("🏭 FACTORY RESET INITIATED");
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
if (!ensureSDCard()) {
|
||||
LOG_ERROR("❌ ConfigManager: Cannot perform factory reset - SD card not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 1: Delete all configuration files
|
||||
LOG_INFO("🗑️ Step 1: Deleting all configuration files from SD card...");
|
||||
bool deleteSuccess = clearAllSettings();
|
||||
|
||||
if (!deleteSuccess) {
|
||||
LOG_ERROR("❌ ConfigManager: Factory reset failed - could not delete all settings");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Reset in-memory configuration to defaults
|
||||
LOG_INFO("🔄 Step 2: Resetting in-memory configuration to defaults...");
|
||||
|
||||
// Reset network config (keep device-generated values)
|
||||
networkConfig.useStaticIP = false;
|
||||
networkConfig.ip = IPAddress(0, 0, 0, 0);
|
||||
networkConfig.gateway = IPAddress(0, 0, 0, 0);
|
||||
networkConfig.subnet = IPAddress(0, 0, 0, 0);
|
||||
networkConfig.dns1 = IPAddress(0, 0, 0, 0);
|
||||
networkConfig.dns2 = IPAddress(0, 0, 0, 0);
|
||||
// hostname and apSsid are auto-generated from deviceUID, keep them
|
||||
|
||||
// Reset time config
|
||||
timeConfig.gmtOffsetSec = 0;
|
||||
timeConfig.daylightOffsetSec = 0;
|
||||
|
||||
// Reset bell config
|
||||
createDefaultBellConfig();
|
||||
|
||||
// Reset clock config to defaults
|
||||
clockConfig.c1output = 255;
|
||||
clockConfig.c2output = 255;
|
||||
clockConfig.pulseDuration = 5000;
|
||||
clockConfig.pauseDuration = 2000;
|
||||
clockConfig.physicalHour = 0;
|
||||
clockConfig.physicalMinute = 0;
|
||||
clockConfig.nextOutputIsC1 = true;
|
||||
clockConfig.lastSyncTime = 0;
|
||||
clockConfig.alertType = "OFF";
|
||||
clockConfig.alertRingInterval = 1200;
|
||||
clockConfig.hourBell = 255;
|
||||
clockConfig.halfBell = 255;
|
||||
clockConfig.quarterBell = 255;
|
||||
clockConfig.backlight = false;
|
||||
clockConfig.backlightOutput = 255;
|
||||
clockConfig.backlightOnTime = "18:00";
|
||||
clockConfig.backlightOffTime = "06:00";
|
||||
clockConfig.daytimeSilenceEnabled = false;
|
||||
clockConfig.daytimeSilenceOnTime = "14:00";
|
||||
clockConfig.daytimeSilenceOffTime = "17:00";
|
||||
clockConfig.nighttimeSilenceEnabled = false;
|
||||
clockConfig.nighttimeSilenceOnTime = "22:00";
|
||||
clockConfig.nighttimeSilenceOffTime = "07:00";
|
||||
|
||||
// Note: Device identity (deviceUID, hwType, hwVersion) in NVS is NOT reset
|
||||
// Note: WiFi credentials are handled by WiFiManager, not reset here
|
||||
|
||||
LOG_INFO("✅ Step 2: In-memory configuration reset to defaults");
|
||||
|
||||
LOG_WARNING("✅ FACTORY RESET COMPLETE");
|
||||
LOG_WARNING("🔄 Device will boot with default settings on next restart");
|
||||
LOG_WARNING("🆔 Device identity (UID) preserved in NVS");
|
||||
LOG_INFO("WiFi credentials should be cleared separately using WiFiManager");
|
||||
|
||||
return true;
|
||||
}
|
||||
bool ConfigManager::resetAllToDefaults() {
|
||||
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_WARNING(" 🏭 RESET SETTINGS TO DEFAULTS INITIATED");
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
bool ConfigManager::clearAllSettings() {
|
||||
if (!ensureSDCard()) {
|
||||
LOG_ERROR("ConfigManager: SD card not available for clearing settings");
|
||||
LOG_ERROR("❌ ConfigManager: Cannot perform reset - SD card not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool allDeleted = true;
|
||||
int filesDeleted = 0;
|
||||
int filesFailed = 0;
|
||||
|
||||
// List of all configuration files to delete
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// STEP 1: Delete all configuration files
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const char* settingsFiles[] = {
|
||||
"/settings/deviceConfig.json",
|
||||
"/settings/networkConfig.json",
|
||||
@@ -903,15 +837,14 @@ bool ConfigManager::clearAllSettings() {
|
||||
|
||||
int numFiles = sizeof(settingsFiles) / sizeof(settingsFiles[0]);
|
||||
|
||||
LOG_INFO("ConfigManager: Attempting to delete %d configuration files...", numFiles);
|
||||
LOG_WARNING("🗑️ Step 1: Deleting %d configuration files...", numFiles);
|
||||
|
||||
// Delete each configuration file
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char* filepath = settingsFiles[i];
|
||||
|
||||
if (SD.exists(filepath)) {
|
||||
if (SD.remove(filepath)) {
|
||||
LOG_INFO("✅ Deleted: %s", filepath);
|
||||
LOG_DEBUG("✅ Deleted: %s", filepath);
|
||||
filesDeleted++;
|
||||
} else {
|
||||
LOG_ERROR("❌ Failed to delete: %s", filepath);
|
||||
@@ -923,22 +856,153 @@ bool ConfigManager::clearAllSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
// Also delete the /melodies directory if you want a complete reset
|
||||
// Uncomment if you want to delete melodies too:
|
||||
/*
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// STEP 2: Delete all melodies recursively
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
if (SD.exists("/melodies")) {
|
||||
LOG_INFO("Deleting /melodies directory...");
|
||||
// Note: SD library doesn't have rmdir for non-empty dirs
|
||||
// You'd need to implement recursive delete or just leave melodies
|
||||
LOG_WARNING("🗑️ Step 2: Deleting melody files...");
|
||||
|
||||
File melodiesDir = SD.open("/melodies");
|
||||
if (melodiesDir && melodiesDir.isDirectory()) {
|
||||
int melodiesDeleted = 0;
|
||||
int melodiesFailed = 0;
|
||||
|
||||
File entry = melodiesDir.openNextFile();
|
||||
while (entry) {
|
||||
String entryPath = String("/melodies/") + entry.name();
|
||||
|
||||
if (!entry.isDirectory()) {
|
||||
if (SD.remove(entryPath.c_str())) {
|
||||
LOG_DEBUG("✅ Deleted melody: %s", entryPath.c_str());
|
||||
melodiesDeleted++;
|
||||
} else {
|
||||
LOG_ERROR("❌ Failed to delete melody: %s", entryPath.c_str());
|
||||
melodiesFailed++;
|
||||
allDeleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
entry.close();
|
||||
entry = melodiesDir.openNextFile();
|
||||
}
|
||||
|
||||
melodiesDir.close();
|
||||
|
||||
// Try to remove the empty directory
|
||||
if (SD.rmdir("/melodies")) {
|
||||
LOG_DEBUG("✅ Deleted /melodies directory");
|
||||
} else {
|
||||
LOG_WARNING("⚠️ Could not delete /melodies directory (may not be empty)");
|
||||
}
|
||||
|
||||
LOG_WARNING(" 🎵 Melodies deleted: %d, failed: %d", melodiesDeleted, melodiesFailed);
|
||||
filesDeleted += melodiesDeleted;
|
||||
filesFailed += melodiesFailed;
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("⏩ /melodies directory not found");
|
||||
}
|
||||
*/
|
||||
|
||||
LOG_INFO("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_INFO("📄 Settings cleanup summary:");
|
||||
LOG_INFO(" ✅ Files deleted: %d", filesDeleted);
|
||||
LOG_INFO(" ❌ Files failed: %d", filesFailed);
|
||||
LOG_INFO(" 🔄 Total processed: %d / %d", filesDeleted + filesFailed, numFiles);
|
||||
LOG_INFO("═══════════════════════════════════════════════════════════════════════════");
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// SUMMARY
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
LOG_WARNING("📄 Full reset summary:");
|
||||
LOG_WARNING(" ✅ Files deleted: %d", filesDeleted);
|
||||
LOG_WARNING(" ❌ Files failed: %d", filesFailed);
|
||||
LOG_WARNING(" 🔄 Total processed: %d", filesDeleted + filesFailed);
|
||||
LOG_WARNING("═══════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
LOG_WARNING("✅ RESET TO DEFAULT COMPLETE");
|
||||
LOG_WARNING("🔄 Device will boot with default settings on next restart");
|
||||
LOG_WARNING("🆔 Device identity (UID) preserved");
|
||||
|
||||
return allDeleted;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// GET ALL SETTINGS AS JSON
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
String ConfigManager::getAllSettingsAsJson() const {
|
||||
// Use a large document to hold everything
|
||||
DynamicJsonDocument doc(4096);
|
||||
|
||||
// Device info
|
||||
JsonObject device = doc.createNestedObject("device");
|
||||
device["uid"] = deviceConfig.deviceUID;
|
||||
device["hwType"] = deviceConfig.hwType;
|
||||
device["hwVersion"] = deviceConfig.hwVersion;
|
||||
device["fwVersion"] = deviceConfig.fwVersion;
|
||||
|
||||
// Network config
|
||||
JsonObject network = doc.createNestedObject("network");
|
||||
network["hostname"] = networkConfig.hostname;
|
||||
network["useStaticIP"] = networkConfig.useStaticIP;
|
||||
network["ip"] = networkConfig.ip.toString();
|
||||
network["gateway"] = networkConfig.gateway.toString();
|
||||
network["subnet"] = networkConfig.subnet.toString();
|
||||
network["dns1"] = networkConfig.dns1.toString();
|
||||
network["dns2"] = networkConfig.dns2.toString();
|
||||
|
||||
// Time config
|
||||
JsonObject time = doc.createNestedObject("time");
|
||||
time["ntpServer"] = timeConfig.ntpServer;
|
||||
time["gmtOffsetSec"] = timeConfig.gmtOffsetSec;
|
||||
time["daylightOffsetSec"] = timeConfig.daylightOffsetSec;
|
||||
|
||||
// Bell durations (relay timings)
|
||||
JsonObject bells = doc.createNestedObject("bells");
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
String key = String("b") + (i + 1);
|
||||
bells[key] = bellConfig.durations[i];
|
||||
}
|
||||
|
||||
// Clock configuration
|
||||
JsonObject clock = doc.createNestedObject("clock");
|
||||
clock["enabled"] = clockConfig.enabled;
|
||||
clock["c1output"] = clockConfig.c1output;
|
||||
clock["c2output"] = clockConfig.c2output;
|
||||
clock["pulseDuration"] = clockConfig.pulseDuration;
|
||||
clock["pauseDuration"] = clockConfig.pauseDuration;
|
||||
|
||||
// Clock state
|
||||
JsonObject clockState = doc.createNestedObject("clockState");
|
||||
clockState["physicalHour"] = clockConfig.physicalHour;
|
||||
clockState["physicalMinute"] = clockConfig.physicalMinute;
|
||||
clockState["nextOutputIsC1"] = clockConfig.nextOutputIsC1;
|
||||
clockState["lastSyncTime"] = clockConfig.lastSyncTime;
|
||||
|
||||
// Clock alerts
|
||||
JsonObject alerts = doc.createNestedObject("alerts");
|
||||
alerts["alertType"] = clockConfig.alertType;
|
||||
alerts["alertRingInterval"] = clockConfig.alertRingInterval;
|
||||
alerts["hourBell"] = clockConfig.hourBell;
|
||||
alerts["halfBell"] = clockConfig.halfBell;
|
||||
alerts["quarterBell"] = clockConfig.quarterBell;
|
||||
|
||||
// Clock backlight
|
||||
JsonObject backlight = doc.createNestedObject("backlight");
|
||||
backlight["enabled"] = clockConfig.backlight;
|
||||
backlight["output"] = clockConfig.backlightOutput;
|
||||
backlight["onTime"] = clockConfig.backlightOnTime;
|
||||
backlight["offTime"] = clockConfig.backlightOffTime;
|
||||
|
||||
// Silence periods
|
||||
JsonObject silence = doc.createNestedObject("silence");
|
||||
JsonObject daytime = silence.createNestedObject("daytime");
|
||||
daytime["enabled"] = clockConfig.daytimeSilenceEnabled;
|
||||
daytime["onTime"] = clockConfig.daytimeSilenceOnTime;
|
||||
daytime["offTime"] = clockConfig.daytimeSilenceOffTime;
|
||||
JsonObject nighttime = silence.createNestedObject("nighttime");
|
||||
nighttime["enabled"] = clockConfig.nighttimeSilenceEnabled;
|
||||
nighttime["onTime"] = clockConfig.nighttimeSilenceOnTime;
|
||||
nighttime["offTime"] = clockConfig.nighttimeSilenceOffTime;
|
||||
|
||||
// Serialize to string
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user