Added Set Log Level Commands

This commit is contained in:
2025-10-23 09:34:44 +03:00
parent 470d7bfacc
commit d1835beff5
7 changed files with 199 additions and 9 deletions

View File

@@ -259,7 +259,7 @@ void BellEngine::activateNote(uint16_t note) {
if (bellConfig == 0) continue; if (bellConfig == 0) continue;
// Convert 1-indexed config to 0-indexed bellIndex // Convert 1-indexed config to 0-indexed bellIndex
uint8_t bellIndex = bellConfig-1; uint8_t bellIndex = bellConfig - 1;
// Additional safety check to prevent underflow crashes // Additional safety check to prevent underflow crashes
if (bellIndex >= 255) { if (bellIndex >= 255) {
@@ -311,7 +311,8 @@ void BellEngine::activateNote(uint16_t note) {
LOG_VERBOSE("🔥🔥 BATCH FIRED %d bells SIMULTANEOUSLY!", bellDurations.size()); LOG_VERBOSE("🔥🔥 BATCH FIRED %d bells SIMULTANEOUSLY!", bellDurations.size());
// 🔔 NOTIFY WEBSOCKET CLIENTS OF BELL DINGS! // 🔔 NOTIFY WEBSOCKET CLIENTS OF BELL DINGS!
notifyBellsFired(firedBellIndices); // * deactivated currently, since unstable and causes performance issues *
// notifyBellsFired(firedBellIndices);
} }
} }

View File

@@ -1005,9 +1005,76 @@ void CommandHandler::handleSystemCommand(JsonVariant contents, const MessageCont
handleGetFirmwareStatusCommand(context); handleGetFirmwareStatusCommand(context);
} else if (action == "set_network_config") { } else if (action == "set_network_config") {
handleSetNetworkConfigCommand(contents, context); handleSetNetworkConfigCommand(contents, context);
} else if (action == "set_serial_log_level") {
handleSetSerialLogLevelCommand(contents, context);
} else if (action == "set_sd_log_level") {
handleSetSdLogLevelCommand(contents, context);
} else { } else {
LOG_WARNING("Unknown system action: %s", action.c_str()); LOG_WARNING("Unknown system action: %s", action.c_str());
sendErrorResponse("system", "Unknown action: " + action, context); sendErrorResponse("system", "Unknown action: " + action, context);
} }
} }
// ════════════════════════════════════════════════════════════════════════════
// LOG LEVEL COMMANDS
// ════════════════════════════════════════════════════════════════════════════
void CommandHandler::handleSetSerialLogLevelCommand(JsonVariant contents, const MessageContext& context) {
if (!contents.containsKey("level")) {
sendErrorResponse("set_serial_log_level", "Missing level parameter", context);
return;
}
uint8_t level = contents["level"].as<uint8_t>();
// Set the level in ConfigManager
if (_configManager.setSerialLogLevel(level)) {
// Apply the level to Logging immediately
Logging::setLevel((Logging::LogLevel)level);
// Save to SD card
bool saved = _configManager.saveGeneralConfig();
if (saved) {
sendSuccessResponse("set_serial_log_level",
"Serial log level set to " + String(level) + " and saved", context);
LOG_INFO("Serial log level updated to %d", level);
} else {
sendErrorResponse("set_serial_log_level",
"Log level set but failed to save to SD card", context);
LOG_ERROR("Failed to save serial log level to SD card");
}
} else {
sendErrorResponse("set_serial_log_level",
"Invalid log level (must be 0-5)", context);
}
}
void CommandHandler::handleSetSdLogLevelCommand(JsonVariant contents, const MessageContext& context) {
if (!contents.containsKey("level")) {
sendErrorResponse("set_sd_log_level", "Missing level parameter", context);
return;
}
uint8_t level = contents["level"].as<uint8_t>();
// Set the level in ConfigManager
if (_configManager.setSdLogLevel(level)) {
// Save to SD card
bool saved = _configManager.saveGeneralConfig();
if (saved) {
sendSuccessResponse("set_sd_log_level",
"SD log level set to " + String(level) + " and saved", context);
LOG_INFO("SD log level updated to %d (not yet implemented)", level);
} else {
sendErrorResponse("set_sd_log_level",
"Log level set but failed to save to SD card", context);
LOG_ERROR("Failed to save SD log level to SD card");
}
} else {
sendErrorResponse("set_sd_log_level",
"Invalid log level (must be 0-5)", context);
}
}

View File

@@ -139,4 +139,8 @@ private:
// System Config // System Config
void handleResetDefaultsCommand(const MessageContext& context); void handleResetDefaultsCommand(const MessageContext& context);
// Log Level Commands
void handleSetSerialLogLevelCommand(JsonVariant contents, const MessageContext& context);
void handleSetSdLogLevelCommand(JsonVariant contents, const MessageContext& context);
}; };

View File

@@ -100,6 +100,11 @@ bool ConfigManager::begin() {
saveClockState(); saveClockState();
} }
if (!loadGeneralConfig()) {
LOG_INFO("ConfigManager: Creating default general config file");
saveGeneralConfig();
}
LOG_INFO("ConfigManager: Initialization complete - UID: %s, Hostname: %s", LOG_INFO("ConfigManager: Initialization complete - UID: %s, Hostname: %s",
deviceConfig.deviceUID.c_str(), networkConfig.hostname.c_str()); deviceConfig.deviceUID.c_str(), networkConfig.hostname.c_str());
return true; return true;
@@ -1000,3 +1005,77 @@ String ConfigManager::getAllSettingsAsJson() const {
serializeJson(doc, output); serializeJson(doc, output);
return output; return output;
} }
// ═══════════════════════════════════════════════════════════════════════════════
// GENERAL CONFIGURATION - LOG LEVELS
// ═══════════════════════════════════════════════════════════════════════════════
bool ConfigManager::setSerialLogLevel(uint8_t level) {
if (level > 5) { // Max level is VERBOSE (5)
LOG_WARNING("ConfigManager: Invalid serial log level %d, valid range is 0-5", level);
return false;
}
generalConfig.serialLogLevel = level;
LOG_INFO("ConfigManager: Serial log level set to %d", level);
return true;
}
bool ConfigManager::setSdLogLevel(uint8_t level) {
if (level > 5) { // Max level is VERBOSE (5)
LOG_WARNING("ConfigManager: Invalid SD log level %d, valid range is 0-5", level);
return false;
}
generalConfig.sdLogLevel = level;
LOG_INFO("ConfigManager: SD log level set to %d", level);
return true;
}
bool ConfigManager::loadGeneralConfig() {
if (!ensureSDCard()) return false;
File file = SD.open("/settings/generalConfig.json", FILE_READ);
if (!file) {
LOG_WARNING("ConfigManager: General config file not found - using defaults");
return false;
}
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, file);
file.close();
if (error) {
LOG_ERROR("ConfigManager: Failed to parse general config from SD: %s", error.c_str());
return false;
}
if (doc.containsKey("serialLogLevel")) {
generalConfig.serialLogLevel = doc["serialLogLevel"].as<uint8_t>();
}
if (doc.containsKey("sdLogLevel")) {
generalConfig.sdLogLevel = doc["sdLogLevel"].as<uint8_t>();
}
LOG_INFO("ConfigManager: General config loaded - Serial log level: %d, SD log level: %d",
generalConfig.serialLogLevel, generalConfig.sdLogLevel);
return true;
}
bool ConfigManager::saveGeneralConfig() {
if (!ensureSDCard()) return false;
StaticJsonDocument<256> doc;
doc["serialLogLevel"] = generalConfig.serialLogLevel;
doc["sdLogLevel"] = generalConfig.sdLogLevel;
char buffer[256];
size_t len = serializeJson(doc, buffer, sizeof(buffer));
if (len == 0 || len >= sizeof(buffer)) {
LOG_ERROR("ConfigManager: Failed to serialize general config JSON");
return false;
}
saveFileToSD("/settings", "generalConfig.json", buffer);
LOG_INFO("ConfigManager: General config saved");
return true;
}

View File

@@ -203,6 +203,18 @@ public:
String nighttimeSilenceOffTime = "07:00"; // 🌙 End of nighttime silence String nighttimeSilenceOffTime = "07:00"; // 🌙 End of nighttime silence
}; };
/**
* @struct General Config
* @brief General configuration (loaded from SD)
*
* All clock settings are loaded from SD card at startup.
*/
struct GeneralConfig {
uint8_t serialLogLevel = 0;
uint8_t sdLogLevel = 0;
};
private: private:
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════
// MEMBER VARIABLES - Clean deployment-ready storage // MEMBER VARIABLES - Clean deployment-ready storage
@@ -215,6 +227,7 @@ private:
UpdateConfig updateConfig; UpdateConfig updateConfig;
BellConfig bellConfig; BellConfig bellConfig;
ClockConfig clockConfig; ClockConfig clockConfig;
GeneralConfig generalConfig;
bool sdInitialized = false; bool sdInitialized = false;
std::vector<String> updateServers; std::vector<String> updateServers;
@@ -286,6 +299,7 @@ public:
const UpdateConfig& getUpdateConfig() const { return updateConfig; } const UpdateConfig& getUpdateConfig() const { return updateConfig; }
const BellConfig& getBellConfig() const { return bellConfig; } const BellConfig& getBellConfig() const { return bellConfig; }
const ClockConfig& getClockConfig() const { return clockConfig; } const ClockConfig& getClockConfig() const { return clockConfig; }
const GeneralConfig& getGeneralConfig() const { return generalConfig; }
// Device identity methods (READ-ONLY - factory set via separate factory firmware) // Device identity methods (READ-ONLY - factory set via separate factory firmware)
// These values are loaded ONCE at boot from NVS and kept in RAM // These values are loaded ONCE at boot from NVS and kept in RAM
@@ -376,6 +390,12 @@ public:
void setNighttimeSilenceOnTime(const String& time) { clockConfig.nighttimeSilenceOnTime = time; } void setNighttimeSilenceOnTime(const String& time) { clockConfig.nighttimeSilenceOnTime = time; }
void setNighttimeSilenceOffTime(const String& time) { clockConfig.nighttimeSilenceOffTime = time; } void setNighttimeSilenceOffTime(const String& time) { clockConfig.nighttimeSilenceOffTime = time; }
// General Config methods
bool setSerialLogLevel(uint8_t level);
bool setSdLogLevel(uint8_t level);
bool loadGeneralConfig();
bool saveGeneralConfig();
// Other methods (unchanged) // Other methods (unchanged)
void updateClockAlerts(JsonVariant doc); void updateClockAlerts(JsonVariant doc);
void updateClockBacklight(JsonVariant doc); void updateClockBacklight(JsonVariant doc);
@@ -395,6 +415,7 @@ public:
String getAPSSID() const { return networkConfig.apSsid; } String getAPSSID() const { return networkConfig.apSsid; }
bool isHealthy() const; bool isHealthy() const;
/** /**
* @brief Get all configuration settings as a JSON string * @brief Get all configuration settings as a JSON string
* @return JSON string containing all current settings * @return JSON string containing all current settings

View File

@@ -368,12 +368,23 @@ void Player::onMelodyLoopCompleted() {
// Check if it's time to pause playback // Check if it's time to pause playback
bool Player::timeToPause(unsigned long now) { bool Player::timeToPause(unsigned long now) {
if (isPlaying && continuous_loop) { if (isPlaying && continuous_loop) {
uint64_t timeToPause = segmentStartTime + segment_duration; // Special case: segment_duration = 0 means "one loop only"
LOG_DEBUG("PTL: %llu // NOW: %lu", timeToPause, now); if (segment_duration == 0) {
if (now >= timeToPause && !isPaused) { // Only pause after first loop completes (segmentCmpltTime updated)
LOG_DEBUG("(TimerFunction) Segment Duration Reached. Pausing."); if (segmentCmpltTime > segmentStartTime && !isPaused) {
pauseTime = now; LOG_DEBUG("(TimerFunction) One-loop segment completed. Pausing.");
return true; pauseTime = now;
return true;
}
} else {
// Normal duration-based pausing
uint64_t timeToPause = segmentStartTime + segment_duration;
LOG_DEBUG("PTL: %llu // NOW: %lu", timeToPause, now);
if (now >= timeToPause && !isPaused) {
LOG_DEBUG("(TimerFunction) Segment Duration Reached. Pausing.");
pauseTime = now;
return true;
}
} }
} }
return false; return false;
@@ -385,6 +396,7 @@ bool Player::timeToResume(unsigned long now) {
uint64_t timeToResume = segmentCmpltTime + pause_duration; uint64_t timeToResume = segmentCmpltTime + pause_duration;
if (now >= timeToResume) { if (now >= timeToResume) {
LOG_DEBUG("(TimerFunction) Pause Duration Reached. Resuming"); LOG_DEBUG("(TimerFunction) Pause Duration Reached. Resuming");
segmentStartTime = now; // Reset segment start time for next cycle
return true; return true;
} }
} }

View File

@@ -62,7 +62,7 @@
* 👨‍💻 AUTHOR: BellSystems bonamin * 👨‍💻 AUTHOR: BellSystems bonamin
*/ */
#define FW_VERSION "1.0" #define FW_VERSION "1.2"
/* /*
@@ -70,6 +70,7 @@
* 📅 VERSION HISTORY: * 📅 VERSION HISTORY:
* ═══════════════════════════════════════════════════════════════════════════════ * ═══════════════════════════════════════════════════════════════════════════════
* v0.1 - Vesper Launch Beta * v0.1 - Vesper Launch Beta
* v1.2 - Added Log Level Configuration via App/MQTT
* ═══════════════════════════════════════════════════════════════════════════════ * ═══════════════════════════════════════════════════════════════════════════════
*/ */
@@ -201,6 +202,11 @@ void setup()
// Initialize Configuration (loads factory identity from NVS + user settings from SD) // Initialize Configuration (loads factory identity from NVS + user settings from SD)
configManager.begin(); configManager.begin();
// Apply log level from config (loaded from SD)
uint8_t logLevel = configManager.getGeneralConfig().serialLogLevel;
Logging::setLevel((Logging::LogLevel)logLevel);
LOG_INFO("Log level set to %d from configuration", logLevel);
inputManager.begin(); inputManager.begin();
inputManager.setFactoryResetLongPressCallback(handleFactoryReset); inputManager.setFactoryResetLongPressCallback(handleFactoryReset);