feat: Add per-subsystem log tags to all firmware modules
Refactored logging system to require a TAG as first argument on all LOG_* macros, enabling per-subsystem log filtering and cleaner output. Each subsystem now defines its own TAG (e.g. "BellEngine", "Player"). Also overhauled Logging.hpp/cpp with improved level control and output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
#include "CommandHandler.hpp"
|
||||
|
||||
#define TAG "CommandHandler"
|
||||
#include "../../ConfigManager/ConfigManager.hpp"
|
||||
#include "../../OTAManager/OTAManager.hpp"
|
||||
#include "../../Player/Player.hpp"
|
||||
@@ -65,7 +67,7 @@ void CommandHandler::processCommand(JsonDocument& command, const MessageContext&
|
||||
String cmd = command["cmd"];
|
||||
JsonVariant contents = command["contents"];
|
||||
|
||||
LOG_DEBUG("Processing command: %s from %s", cmd.c_str(),
|
||||
LOG_DEBUG(TAG, "Processing command: %s from %s", cmd.c_str(),
|
||||
context.source == MessageSource::MQTT ? "MQTT" : "WebSocket");
|
||||
|
||||
if (cmd == "ping") {
|
||||
@@ -85,7 +87,7 @@ void CommandHandler::processCommand(JsonDocument& command, const MessageContext&
|
||||
} else if (cmd == "system") {
|
||||
handleSystemCommand(contents, context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown command received: %s", cmd.c_str());
|
||||
LOG_WARNING(TAG, "Unknown command received: %s", cmd.c_str());
|
||||
sendErrorResponse("unknown_command", "Command not recognized: " + cmd, context);
|
||||
}
|
||||
}
|
||||
@@ -146,7 +148,7 @@ void CommandHandler::handleIdentifyCommand(JsonVariant contents, const MessageCo
|
||||
|
||||
// 🛡️ SAFETY CHECK: Ensure ClientManager reference is set
|
||||
if (!_clientManager) {
|
||||
LOG_ERROR("ClientManager reference not set in CommandHandler!");
|
||||
LOG_ERROR(TAG, "ClientManager reference not set in CommandHandler!");
|
||||
sendErrorResponse("identify", "Internal error: ClientManager not available", context);
|
||||
return;
|
||||
}
|
||||
@@ -168,7 +170,7 @@ void CommandHandler::handleIdentifyCommand(JsonVariant contents, const MessageCo
|
||||
if (deviceType != ClientManager::DeviceType::UNKNOWN) {
|
||||
_clientManager->updateClientType(context.clientId, deviceType);
|
||||
sendSuccessResponse("identify", "Device identified as " + deviceTypeStr, context);
|
||||
LOG_INFO("Client #%u identified as %s device", context.clientId, deviceTypeStr.c_str());
|
||||
LOG_INFO(TAG, "Client #%u identified as %s device", context.clientId, deviceTypeStr.c_str());
|
||||
} else {
|
||||
sendErrorResponse("identify", "Invalid device_type. Use 'master' or 'secondary'", context);
|
||||
}
|
||||
@@ -184,7 +186,7 @@ void CommandHandler::handlePlaybackCommand(JsonVariant contents, const MessageCo
|
||||
sendErrorResponse("playback", "Playback command failed", context);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Player reference not set");
|
||||
LOG_ERROR(TAG, "Player reference not set");
|
||||
sendErrorResponse("playback", "Player not available", context);
|
||||
}
|
||||
}
|
||||
@@ -196,7 +198,7 @@ void CommandHandler::handleFileManagerCommand(JsonVariant contents, const Messag
|
||||
}
|
||||
|
||||
String action = contents["action"];
|
||||
LOG_DEBUG("Processing file manager action: %s", action.c_str());
|
||||
LOG_DEBUG(TAG, "Processing file manager action: %s", action.c_str());
|
||||
|
||||
if (action == "list_melodies") {
|
||||
handleListMelodiesCommand(context);
|
||||
@@ -205,7 +207,7 @@ void CommandHandler::handleFileManagerCommand(JsonVariant contents, const Messag
|
||||
} else if (action == "delete_melody") {
|
||||
handleDeleteMelodyCommand(contents, context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown file manager action: %s", action.c_str());
|
||||
LOG_WARNING(TAG, "Unknown file manager action: %s", action.c_str());
|
||||
sendErrorResponse("file_manager", "Unknown action: " + action, context);
|
||||
}
|
||||
}
|
||||
@@ -217,14 +219,14 @@ void CommandHandler::handleRelaySetupCommand(JsonVariant contents, const Message
|
||||
}
|
||||
|
||||
String action = contents["action"];
|
||||
LOG_DEBUG("Processing relay setup action: %s", action.c_str());
|
||||
LOG_DEBUG(TAG, "Processing relay setup action: %s", action.c_str());
|
||||
|
||||
if (action == "set_timings") {
|
||||
handleSetRelayTimersCommand(contents, context);
|
||||
} else if (action == "set_outputs") {
|
||||
handleSetRelayOutputsCommand(contents, context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown relay setup action: %s", action.c_str());
|
||||
LOG_WARNING(TAG, "Unknown relay setup action: %s", action.c_str());
|
||||
sendErrorResponse("relay_setup", "Unknown action: " + action, context);
|
||||
}
|
||||
}
|
||||
@@ -236,7 +238,7 @@ void CommandHandler::handleClockSetupCommand(JsonVariant contents, const Message
|
||||
}
|
||||
|
||||
String action = contents["action"];
|
||||
LOG_DEBUG("Processing clock setup action: %s", action.c_str());
|
||||
LOG_DEBUG(TAG, "Processing clock setup action: %s", action.c_str());
|
||||
|
||||
if (action == "set_outputs") {
|
||||
handleSetClockOutputsCommand(contents, context);
|
||||
@@ -257,7 +259,7 @@ void CommandHandler::handleClockSetupCommand(JsonVariant contents, const Message
|
||||
} else if (action == "set_enabled") {
|
||||
handleSetClockEnabledCommand(contents, context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown clock setup action: %s", action.c_str());
|
||||
LOG_WARNING(TAG, "Unknown clock setup action: %s", action.c_str());
|
||||
sendErrorResponse("clock_setup", "Unknown action: " + action, context);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +271,7 @@ void CommandHandler::handleSystemInfoCommand(JsonVariant contents, const Message
|
||||
}
|
||||
|
||||
String action = contents["action"];
|
||||
LOG_DEBUG("Processing system info action: %s", action.c_str());
|
||||
LOG_DEBUG(TAG, "Processing system info action: %s", action.c_str());
|
||||
|
||||
if (action == "report_status") {
|
||||
handleStatusCommand(context);
|
||||
@@ -286,7 +288,7 @@ void CommandHandler::handleSystemInfoCommand(JsonVariant contents, const Message
|
||||
} else if (action == "sync_time_to_lcd") {
|
||||
handleSyncTimeToLcdCommand(context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown system info action: %s", action.c_str());
|
||||
LOG_WARNING(TAG, "Unknown system info action: %s", action.c_str());
|
||||
sendErrorResponse("system_info", "Unknown action: " + action, context);
|
||||
}
|
||||
}
|
||||
@@ -303,7 +305,7 @@ void CommandHandler::handleListMelodiesCommand(const MessageContext& context) {
|
||||
DeserializationError error = deserializeJson(doc, fileListJson);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse file list JSON: %s", error.c_str());
|
||||
LOG_ERROR(TAG, "Failed to parse file list JSON: %s", error.c_str());
|
||||
sendErrorResponse("list_melodies", "Failed to parse file list", context);
|
||||
return;
|
||||
}
|
||||
@@ -362,14 +364,14 @@ void CommandHandler::handleSetRelayTimersCommand(JsonVariant contents, const Mes
|
||||
bool saved = _configManager.saveBellDurations();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_relay_timers", "Relay timers updated and saved", context);
|
||||
LOG_INFO("Relay timers updated and saved successfully");
|
||||
LOG_INFO(TAG, "Relay timers updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_relay_timers", "Failed to save relay timers to SD card", context);
|
||||
LOG_ERROR("Failed to save relay timers configuration");
|
||||
LOG_ERROR(TAG, "Failed to save relay timers configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_relay_timers", "Failed to update relay timers", context);
|
||||
LOG_ERROR("Exception occurred while updating relay timers");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating relay timers");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,14 +382,14 @@ void CommandHandler::handleSetRelayOutputsCommand(JsonVariant contents, const Me
|
||||
bool saved = _configManager.saveBellOutputs();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_relay_outputs", "Relay outputs updated and saved", context);
|
||||
LOG_INFO("Relay outputs updated and saved successfully");
|
||||
LOG_INFO(TAG, "Relay outputs updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_relay_outputs", "Failed to save relay outputs to SD card", context);
|
||||
LOG_ERROR("Failed to save relay outputs configuration");
|
||||
LOG_ERROR(TAG, "Failed to save relay outputs configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_relay_outputs", "Failed to update relay outputs", context);
|
||||
LOG_ERROR("Exception occurred while updating relay outputs");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating relay outputs");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,14 +400,14 @@ void CommandHandler::handleSetClockOutputsCommand(JsonVariant contents, const Me
|
||||
bool saved = _configManager.saveClockConfig();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_clock_outputs", "Clock outputs updated and saved", context);
|
||||
LOG_INFO("Clock outputs updated and saved successfully");
|
||||
LOG_INFO(TAG, "Clock outputs updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_clock_outputs", "Failed to save clock outputs to SD card", context);
|
||||
LOG_ERROR("Failed to save clock outputs configuration");
|
||||
LOG_ERROR(TAG, "Failed to save clock outputs configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_outputs", "Failed to update clock outputs", context);
|
||||
LOG_ERROR("Exception occurred while updating clock outputs");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock outputs");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,14 +418,14 @@ void CommandHandler::handleSetClockTimingsCommand(JsonVariant contents, const Me
|
||||
bool saved = _configManager.saveClockConfig();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_clock_timings", "Clock timings updated and saved", context);
|
||||
LOG_INFO("Clock timings updated and saved successfully");
|
||||
LOG_INFO(TAG, "Clock timings updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_clock_timings", "Failed to save clock timings to SD card", context);
|
||||
LOG_ERROR("Failed to save clock timings configuration");
|
||||
LOG_ERROR(TAG, "Failed to save clock timings configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_timings", "Failed to update clock timings", context);
|
||||
LOG_ERROR("Exception occurred while updating clock timings");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock timings");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,14 +436,14 @@ void CommandHandler::handleSetClockAlertsCommand(JsonVariant contents, const Mes
|
||||
bool saved = _configManager.saveClockConfig();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_clock_alerts", "Clock alerts updated and saved", context);
|
||||
LOG_INFO("Clock alerts updated and saved successfully");
|
||||
LOG_INFO(TAG, "Clock alerts updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_clock_alerts", "Failed to save clock alerts to SD card", context);
|
||||
LOG_ERROR("Failed to save clock alerts configuration");
|
||||
LOG_ERROR(TAG, "Failed to save clock alerts configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_alerts", "Failed to update clock alerts", context);
|
||||
LOG_ERROR("Exception occurred while updating clock alerts");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock alerts");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,14 +454,14 @@ void CommandHandler::handleSetClockBacklightCommand(JsonVariant contents, const
|
||||
bool saved = _configManager.saveClockConfig();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_clock_backlight", "Clock backlight updated and saved", context);
|
||||
LOG_INFO("Clock backlight updated and saved successfully");
|
||||
LOG_INFO(TAG, "Clock backlight updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_clock_backlight", "Failed to save clock backlight to SD card", context);
|
||||
LOG_ERROR("Failed to save clock backlight configuration");
|
||||
LOG_ERROR(TAG, "Failed to save clock backlight configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_backlight", "Failed to update clock backlight", context);
|
||||
LOG_ERROR("Exception occurred while updating clock backlight");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock backlight");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,14 +472,14 @@ void CommandHandler::handleSetClockSilenceCommand(JsonVariant contents, const Me
|
||||
bool saved = _configManager.saveClockConfig();
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_clock_silence", "Clock silence periods updated and saved", context);
|
||||
LOG_INFO("Clock silence periods updated and saved successfully");
|
||||
LOG_INFO(TAG, "Clock silence periods updated and saved successfully");
|
||||
} else {
|
||||
sendErrorResponse("set_clock_silence", "Failed to save clock silence configuration to SD card", context);
|
||||
LOG_ERROR("Failed to save clock silence configuration");
|
||||
LOG_ERROR(TAG, "Failed to save clock silence configuration");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_silence", "Failed to update clock silence periods", context);
|
||||
LOG_ERROR("Exception occurred while updating clock silence periods");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock silence periods");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +516,7 @@ void CommandHandler::handleSetRtcTimeCommand(JsonVariant contents, const Message
|
||||
// Update timezone configuration
|
||||
_configManager.updateTimeConfig(baseGmtOffset, dstOffset);
|
||||
|
||||
LOG_INFO("Timezone updated: %s (GMT%+ld, DST%+ld)",
|
||||
LOG_INFO(TAG, "Timezone updated: %s (GMT%+ld, DST%+ld)",
|
||||
timezoneName.c_str(), baseGmtOffset/3600, dstOffset/3600);
|
||||
|
||||
// Apply total offset to timestamp
|
||||
@@ -529,11 +531,11 @@ void CommandHandler::handleSetRtcTimeCommand(JsonVariant contents, const Message
|
||||
if (verifyTime > 0 && abs((long)verifyTime - (long)localTimestamp) < 5) { // Allow 5 second tolerance
|
||||
sendSuccessResponse("set_rtc_time",
|
||||
"RTC time and timezone updated successfully", context);
|
||||
LOG_INFO("RTC time set with timezone: UTC %lu + %ld = local %lu",
|
||||
LOG_INFO(TAG, "RTC time set with timezone: UTC %lu + %ld = local %lu",
|
||||
timestamp, totalOffset, localTimestamp);
|
||||
} else {
|
||||
sendErrorResponse("set_rtc_time", "Failed to verify RTC time was set correctly", context);
|
||||
LOG_ERROR("RTC time verification failed - expected: %lu, got: %lu", localTimestamp, verifyTime);
|
||||
LOG_ERROR(TAG, "RTC time verification failed - expected: %lu, got: %lu", localTimestamp, verifyTime);
|
||||
}
|
||||
} else {
|
||||
// Legacy method: Use device's existing timezone config
|
||||
@@ -543,10 +545,10 @@ void CommandHandler::handleSetRtcTimeCommand(JsonVariant contents, const Message
|
||||
unsigned long verifyTime = _timeKeeper->getTime();
|
||||
if (verifyTime > 0 && abs((long)verifyTime - (long)timestamp) < 5) { // Allow 5 second tolerance
|
||||
sendSuccessResponse("set_rtc_time", "RTC time updated successfully", context);
|
||||
LOG_INFO("RTC time set using device timezone config: %lu", timestamp);
|
||||
LOG_INFO(TAG, "RTC time set using device timezone config: %lu", timestamp);
|
||||
} else {
|
||||
sendErrorResponse("set_rtc_time", "Failed to verify RTC time was set correctly", context);
|
||||
LOG_ERROR("RTC time verification failed - expected: %lu, got: %lu", timestamp, verifyTime);
|
||||
LOG_ERROR(TAG, "RTC time verification failed - expected: %lu, got: %lu", timestamp, verifyTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,11 +587,11 @@ void CommandHandler::handleSetPhysicalClockTimeCommand(JsonVariant contents, con
|
||||
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_physical_clock_time", "Physical clock time updated and saved successfully", context);
|
||||
LOG_INFO("Physical clock time set to %02d:%02d (12h: %02d:%02d) and saved to SD",
|
||||
LOG_INFO(TAG, "Physical clock time set to %02d:%02d (12h: %02d:%02d) and saved to SD",
|
||||
hour, minute, clockHour, minute);
|
||||
} else {
|
||||
sendErrorResponse("set_physical_clock_time", "Physical clock time updated but failed to save to SD card", context);
|
||||
LOG_ERROR("Physical clock time set to %02d:%02d but failed to save to SD", hour, minute);
|
||||
LOG_ERROR(TAG, "Physical clock time set to %02d:%02d but failed to save to SD", hour, minute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,12 +603,12 @@ void CommandHandler::handlePauseClockUpdatesCommand(JsonVariant contents, const
|
||||
if (contents["action"] == "pause_clock_updates") {
|
||||
_timeKeeper->pauseClockUpdates();
|
||||
sendSuccessResponse("pause_clock_updates", "Clock updates paused", context);
|
||||
LOG_DEBUG("Clock updates paused");
|
||||
LOG_DEBUG(TAG, "Clock updates paused");
|
||||
return;
|
||||
} else if (contents["action"] == "resume_clock_updates") {
|
||||
_timeKeeper->resumeClockUpdates();
|
||||
sendSuccessResponse("resume_clock_updates", "Clock updates resumed", context);
|
||||
LOG_DEBUG("Clock updates resumed");
|
||||
LOG_DEBUG(TAG, "Clock updates resumed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -626,14 +628,14 @@ void CommandHandler::handleSetClockEnabledCommand(JsonVariant contents, const Me
|
||||
if (saved) {
|
||||
String status = enabled ? "enabled" : "disabled";
|
||||
sendSuccessResponse("set_clock_enabled", "Clock " + status + " and saved successfully", context);
|
||||
LOG_INFO("Clock %s via remote command", status.c_str());
|
||||
LOG_INFO(TAG, "Clock %s via remote command", status.c_str());
|
||||
} else {
|
||||
sendErrorResponse("set_clock_enabled", "Clock setting updated but failed to save to SD card", context);
|
||||
LOG_ERROR("Failed to save clock enabled setting to SD card");
|
||||
LOG_ERROR(TAG, "Failed to save clock enabled setting to SD card");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_clock_enabled", "Failed to update clock enabled setting", context);
|
||||
LOG_ERROR("Exception occurred while updating clock enabled setting");
|
||||
LOG_ERROR(TAG, "Exception occurred while updating clock enabled setting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,14 +670,14 @@ void CommandHandler::handleGetDeviceTimeCommand(const MessageContext& context) {
|
||||
response["payload"]["local_timestamp"] = millis() / 1000;
|
||||
response["payload"]["utc_timestamp"] = millis() / 1000;
|
||||
response["payload"]["rtc_available"] = false;
|
||||
LOG_WARNING("TimeKeeper reference not set for device time request");
|
||||
LOG_WARNING(TAG, "TimeKeeper reference not set for device time request");
|
||||
}
|
||||
|
||||
String responseStr;
|
||||
serializeJson(response, responseStr);
|
||||
sendResponse(responseStr, context);
|
||||
|
||||
LOG_DEBUG("Device time requested");
|
||||
LOG_DEBUG(TAG, "Device time requested");
|
||||
}
|
||||
|
||||
void CommandHandler::handleGetClockTimeCommand(const MessageContext& context) {
|
||||
@@ -694,7 +696,7 @@ void CommandHandler::handleGetClockTimeCommand(const MessageContext& context) {
|
||||
serializeJson(response, responseStr);
|
||||
sendResponse(responseStr, context);
|
||||
|
||||
LOG_DEBUG("Physical clock time requested: %02d:%02d (last sync: %lu)",
|
||||
LOG_DEBUG(TAG, "Physical clock time requested: %02d:%02d (last sync: %lu)",
|
||||
_configManager.getPhysicalClockHour(),
|
||||
_configManager.getPhysicalClockMinute(),
|
||||
_configManager.getLastSyncTime());
|
||||
@@ -716,16 +718,16 @@ void CommandHandler::handleCommitFirmwareCommand(const MessageContext& context)
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("💾 Manual firmware commit requested via %s",
|
||||
LOG_INFO(TAG, "💾 Manual firmware commit requested via %s",
|
||||
context.source == MessageSource::MQTT ? "MQTT" : "WebSocket");
|
||||
|
||||
try {
|
||||
_firmwareValidator->commitFirmware();
|
||||
sendSuccessResponse("commit_firmware", "Firmware committed successfully", context);
|
||||
LOG_INFO("✅ Firmware manually committed - system is now stable");
|
||||
LOG_INFO(TAG, "✅ Firmware manually committed - system is now stable");
|
||||
} catch (...) {
|
||||
sendErrorResponse("commit_firmware", "Failed to commit firmware", context);
|
||||
LOG_ERROR("❌ Failed to commit firmware");
|
||||
LOG_ERROR(TAG, "❌ Failed to commit firmware");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,18 +737,18 @@ void CommandHandler::handleRollbackFirmwareCommand(const MessageContext& context
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WARNING("🔄 Manual firmware rollback requested via %s",
|
||||
LOG_WARNING(TAG, "🔄 Manual firmware rollback requested via %s",
|
||||
context.source == MessageSource::MQTT ? "MQTT" : "WebSocket");
|
||||
|
||||
try {
|
||||
_firmwareValidator->rollbackFirmware();
|
||||
sendSuccessResponse("rollback_firmware", "Firmware rollback initiated - device will reboot", context);
|
||||
LOG_WARNING("🔄 Firmware rollback initiated - device should reboot shortly");
|
||||
LOG_WARNING(TAG, "🔄 Firmware rollback initiated - device should reboot shortly");
|
||||
|
||||
// Device should reboot automatically, but this response might not be sent
|
||||
} catch (...) {
|
||||
sendErrorResponse("rollback_firmware", "Failed to initiate firmware rollback", context);
|
||||
LOG_ERROR("❌ Failed to initiate firmware rollback");
|
||||
LOG_ERROR(TAG, "❌ Failed to initiate firmware rollback");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +822,7 @@ void CommandHandler::handleGetFirmwareStatusCommand(const MessageContext& contex
|
||||
serializeJson(response, responseStr);
|
||||
sendResponse(responseStr, context);
|
||||
|
||||
LOG_DEBUG("Firmware status requested: %s", stateStr.c_str());
|
||||
LOG_DEBUG(TAG, "Firmware status requested: %s", stateStr.c_str());
|
||||
}
|
||||
|
||||
void CommandHandler::handleNetworkInfoCommand(const MessageContext& context) {
|
||||
@@ -839,7 +841,7 @@ void CommandHandler::handleNetworkInfoCommand(const MessageContext& context) {
|
||||
}
|
||||
|
||||
void CommandHandler::handleGetFullSettingsCommand(const MessageContext& context) {
|
||||
LOG_DEBUG("Full settings requested");
|
||||
LOG_DEBUG(TAG, "Full settings requested");
|
||||
|
||||
// Get all settings as JSON string from ConfigManager
|
||||
String settingsJson = _configManager.getAllSettingsAsJson();
|
||||
@@ -854,7 +856,7 @@ void CommandHandler::handleGetFullSettingsCommand(const MessageContext& context)
|
||||
DeserializationError error = deserializeJson(settingsDoc, settingsJson);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse settings JSON: %s", error.c_str());
|
||||
LOG_ERROR(TAG, "Failed to parse settings JSON: %s", error.c_str());
|
||||
sendErrorResponse("get_full_settings", "Failed to serialize settings", context);
|
||||
return;
|
||||
}
|
||||
@@ -865,7 +867,7 @@ void CommandHandler::handleGetFullSettingsCommand(const MessageContext& context)
|
||||
serializeJson(response, responseStr);
|
||||
sendResponse(responseStr, context);
|
||||
|
||||
LOG_DEBUG("Full settings sent (%d bytes)", responseStr.length());
|
||||
LOG_DEBUG(TAG, "Full settings sent (%d bytes)", responseStr.length());
|
||||
}
|
||||
|
||||
void CommandHandler::handleSyncTimeToLcdCommand(const MessageContext& context) {
|
||||
@@ -880,7 +882,7 @@ void CommandHandler::handleSyncTimeToLcdCommand(const MessageContext& context) {
|
||||
} else {
|
||||
// Fallback to millis if TimeKeeper not available
|
||||
localTimestamp = millis() / 1000;
|
||||
LOG_WARNING("TimeKeeper not available for LCD time sync");
|
||||
LOG_WARNING(TAG, "TimeKeeper not available for LCD time sync");
|
||||
}
|
||||
|
||||
// Get timezone offset from ConfigManager (in seconds)
|
||||
@@ -897,7 +899,7 @@ void CommandHandler::handleSyncTimeToLcdCommand(const MessageContext& context) {
|
||||
serializeJson(response, responseStr);
|
||||
sendResponse(responseStr, context);
|
||||
|
||||
LOG_DEBUG("LCD time sync: UTC=%lu, offset=%ld", utcTimestamp, totalOffset);
|
||||
LOG_DEBUG(TAG, "LCD time sync: UTC=%lu, offset=%ld", utcTimestamp, totalOffset);
|
||||
}
|
||||
|
||||
void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const MessageContext& context) {
|
||||
@@ -933,7 +935,7 @@ void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const M
|
||||
hostname = newHostname;
|
||||
configChanged = true;
|
||||
needsReboot = true;
|
||||
LOG_INFO("Hostname will be updated to: %s", hostname.c_str());
|
||||
LOG_INFO(TAG, "Hostname will be updated to: %s", hostname.c_str());
|
||||
} else {
|
||||
sendErrorResponse("set_network_config", "Invalid hostname (must be 1-32 characters)", context);
|
||||
return;
|
||||
@@ -975,9 +977,9 @@ void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const M
|
||||
dns2.fromString(contents["dns2"].as<String>());
|
||||
}
|
||||
|
||||
LOG_INFO("Static IP configuration will be applied: %s", ip.toString().c_str());
|
||||
LOG_INFO(TAG, "Static IP configuration will be applied: %s", ip.toString().c_str());
|
||||
} else {
|
||||
LOG_INFO("DHCP mode will be enabled");
|
||||
LOG_INFO(TAG, "DHCP mode will be enabled");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,10 +998,10 @@ void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const M
|
||||
responseMsg += ". RESTART DEVICE to apply changes";
|
||||
}
|
||||
sendSuccessResponse("set_network_config", responseMsg, context);
|
||||
LOG_INFO("✅ Network configuration saved to SD card");
|
||||
LOG_INFO(TAG, "✅ Network configuration saved to SD card");
|
||||
} else {
|
||||
sendErrorResponse("set_network_config", "Configuration updated but failed to save to SD card", context);
|
||||
LOG_ERROR("❌ Failed to save network configuration to SD card");
|
||||
LOG_ERROR(TAG, "❌ Failed to save network configuration to SD card");
|
||||
}
|
||||
} else {
|
||||
sendSuccessResponse("set_network_config", "No changes detected", context);
|
||||
@@ -1007,10 +1009,10 @@ void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const M
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
sendErrorResponse("set_network_config", String("Exception: ") + e.what(), context);
|
||||
LOG_ERROR("Exception in handleSetNetworkConfigCommand: %s", e.what());
|
||||
LOG_ERROR(TAG, "Exception in handleSetNetworkConfigCommand: %s", e.what());
|
||||
} catch (...) {
|
||||
sendErrorResponse("set_network_config", "Unknown error occurred", context);
|
||||
LOG_ERROR("Unknown exception in handleSetNetworkConfigCommand");
|
||||
LOG_ERROR(TAG, "Unknown exception in handleSetNetworkConfigCommand");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1022,7 @@ void CommandHandler::handleSetNetworkConfigCommand(JsonVariant contents, const M
|
||||
|
||||
void CommandHandler::handleResetDefaultsCommand(const MessageContext& context) {
|
||||
|
||||
LOG_WARNING("⚠️ Factory reset requested. Proceeding...");
|
||||
LOG_WARNING(TAG, "⚠️ Factory reset requested. Proceeding...");
|
||||
|
||||
try {
|
||||
// Reset all configurations to defaults
|
||||
@@ -1028,14 +1030,14 @@ void CommandHandler::handleResetDefaultsCommand(const MessageContext& context) {
|
||||
|
||||
if (resetComplete) {
|
||||
sendSuccessResponse("reset_defaults", "Reset to Defaults completed. Device will Restart to apply changes.", context);
|
||||
LOG_WARNING("✅ Factory reset completed and all configurations saved to SD card");
|
||||
LOG_WARNING(TAG, "✅ Factory reset completed and all configurations saved to SD card");
|
||||
} else {
|
||||
sendErrorResponse("reset_defaults", "Reset to Defaults applied but failed to save some configurations to SD card", context);
|
||||
LOG_ERROR("❌ Reset to Defaults applied but failed to save some configurations to SD card");
|
||||
LOG_ERROR(TAG, "❌ Reset to Defaults applied but failed to save some configurations to SD card");
|
||||
}
|
||||
} catch (...) {
|
||||
sendErrorResponse("reset_defaults", "Failed to perform Reset to Defaults", context);
|
||||
LOG_ERROR("❌ Exception occurred during Resetting to Defaults");
|
||||
LOG_ERROR(TAG, "❌ Exception occurred during Resetting to Defaults");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1053,7 +1055,7 @@ void CommandHandler::handleSystemCommand(JsonVariant contents, const MessageCont
|
||||
}
|
||||
|
||||
String action = contents["action"];
|
||||
LOG_DEBUG("Processing system action: %s", action.c_str());
|
||||
LOG_DEBUG(TAG, "Processing system action: %s", action.c_str());
|
||||
|
||||
if (action == "status") {
|
||||
handleStatusCommand(context);
|
||||
@@ -1082,7 +1084,7 @@ void CommandHandler::handleSystemCommand(JsonVariant contents, const MessageCont
|
||||
} else if (action == "custom_update") {
|
||||
handleCustomUpdateCommand(contents, context);
|
||||
} else {
|
||||
LOG_WARNING("Unknown system action: %s", action.c_str());
|
||||
LOG_WARNING(TAG, "Unknown system action: %s", action.c_str());
|
||||
sendErrorResponse("system", "Unknown action: " + action, context);
|
||||
}
|
||||
}
|
||||
@@ -1110,11 +1112,11 @@ void CommandHandler::handleSetSerialLogLevelCommand(JsonVariant contents, const
|
||||
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);
|
||||
LOG_INFO(TAG, "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");
|
||||
LOG_ERROR(TAG, "Failed to save serial log level to SD card");
|
||||
}
|
||||
} else {
|
||||
sendErrorResponse("set_serial_log_level",
|
||||
@@ -1132,17 +1134,20 @@ void CommandHandler::handleSetSdLogLevelCommand(JsonVariant contents, const Mess
|
||||
|
||||
// Set the level in ConfigManager
|
||||
if (_configManager.setSdLogLevel(level)) {
|
||||
// Apply immediately
|
||||
Logging::setSdLevel((Logging::LogLevel)level);
|
||||
|
||||
// Save to SD card
|
||||
bool saved = _configManager.saveGeneralConfig();
|
||||
|
||||
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_sd_log_level",
|
||||
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);
|
||||
LOG_INFO(TAG, "SD log level updated to %d", 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");
|
||||
LOG_ERROR(TAG, "Failed to save SD log level to SD card");
|
||||
}
|
||||
} else {
|
||||
sendErrorResponse("set_sd_log_level",
|
||||
@@ -1169,11 +1174,11 @@ void CommandHandler::handleSetMqttLogLevelCommand(JsonVariant contents, const Me
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_mqtt_log_level",
|
||||
"MQTT log level set to " + String(level) + " and saved", context);
|
||||
LOG_INFO("MQTT log level updated to %d", level);
|
||||
LOG_INFO(TAG, "MQTT log level updated to %d", level);
|
||||
} else {
|
||||
sendErrorResponse("set_mqtt_log_level",
|
||||
"Log level set but failed to save to SD card", context);
|
||||
LOG_ERROR("Failed to save MQTT log level to SD card");
|
||||
LOG_ERROR(TAG, "Failed to save MQTT log level to SD card");
|
||||
}
|
||||
} else {
|
||||
sendErrorResponse("set_mqtt_log_level",
|
||||
@@ -1198,7 +1203,7 @@ void CommandHandler::handleSetMqttEnabledCommand(JsonVariant contents, const Mes
|
||||
if (saved) {
|
||||
sendSuccessResponse("set_mqtt_enabled",
|
||||
String("MQTT ") + (enabled ? "enabled" : "disabled") + " and saved", context);
|
||||
LOG_INFO("MQTT %s by user command", enabled ? "enabled" : "disabled");
|
||||
LOG_INFO(TAG, "MQTT %s by user command", enabled ? "enabled" : "disabled");
|
||||
|
||||
// If disabling, disconnect MQTT immediately
|
||||
// If enabling, trigger connection attempt
|
||||
@@ -1209,12 +1214,12 @@ void CommandHandler::handleSetMqttEnabledCommand(JsonVariant contents, const Mes
|
||||
_communicationRouter->getMQTTClient().connect();
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING("CommunicationRouter reference not set - cannot control MQTT");
|
||||
LOG_WARNING(TAG, "CommunicationRouter reference not set - cannot control MQTT");
|
||||
}
|
||||
} else {
|
||||
sendErrorResponse("set_mqtt_enabled",
|
||||
"MQTT state changed but failed to save to SD card", context);
|
||||
LOG_ERROR("Failed to save MQTT enabled state to SD card");
|
||||
LOG_ERROR(TAG, "Failed to save MQTT enabled state to SD card");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1223,7 +1228,7 @@ void CommandHandler::handleSetMqttEnabledCommand(JsonVariant contents, const Mes
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
void CommandHandler::handleRestartCommand(const MessageContext& context) {
|
||||
LOG_WARNING("🔄 Device restart requested via command");
|
||||
LOG_WARNING(TAG, "🔄 Device restart requested via command");
|
||||
sendSuccessResponse("restart", "Device will restart in 2 seconds", context);
|
||||
|
||||
// Small delay to ensure response is sent
|
||||
@@ -1238,12 +1243,12 @@ void CommandHandler::handleRestartCommand(const MessageContext& context) {
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
void CommandHandler::handleForceUpdateCommand(JsonVariant contents, const MessageContext& context) {
|
||||
LOG_WARNING("🔄 Force OTA update requested via command");
|
||||
LOG_WARNING(TAG, "🔄 Force OTA update requested via command");
|
||||
|
||||
// Check if player is active
|
||||
if (_player && _player->isCurrentlyPlaying()) {
|
||||
sendErrorResponse("force_update", "Cannot update while playback is active", context);
|
||||
LOG_WARNING("Force update rejected - player is active");
|
||||
LOG_WARNING(TAG, "Force update rejected - player is active");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1264,7 +1269,7 @@ void CommandHandler::handleForceUpdateCommand(JsonVariant contents, const Messag
|
||||
|
||||
// Note: If update succeeds, device will reboot and this won't be reached
|
||||
if (!result) {
|
||||
LOG_ERROR("Force update failed");
|
||||
LOG_ERROR(TAG, "Force update failed");
|
||||
// Error response may not be received if we already restarted
|
||||
}
|
||||
}
|
||||
@@ -1274,7 +1279,7 @@ void CommandHandler::handleForceUpdateCommand(JsonVariant contents, const Messag
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
void CommandHandler::handleCustomUpdateCommand(JsonVariant contents, const MessageContext& context) {
|
||||
LOG_WARNING("🔥 Custom OTA update requested via command");
|
||||
LOG_WARNING(TAG, "🔥 Custom OTA update requested via command");
|
||||
|
||||
// Validate required parameters
|
||||
if (!contents.containsKey("firmware_url")) {
|
||||
@@ -1295,11 +1300,11 @@ void CommandHandler::handleCustomUpdateCommand(JsonVariant contents, const Messa
|
||||
// Check if player is active
|
||||
if (_player && _player->isCurrentlyPlaying()) {
|
||||
sendErrorResponse("custom_update", "Cannot update while playback is active", context);
|
||||
LOG_WARNING("Custom update rejected - player is active");
|
||||
LOG_WARNING(TAG, "Custom update rejected - player is active");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Custom update: URL=%s, Checksum=%s, Size=%u, Version=%u",
|
||||
LOG_INFO(TAG, "Custom update: URL=%s, Checksum=%s, Size=%u, Version=%u",
|
||||
firmwareUrl.c_str(),
|
||||
checksum.isEmpty() ? "none" : checksum.c_str(),
|
||||
fileSize,
|
||||
@@ -1316,7 +1321,7 @@ void CommandHandler::handleCustomUpdateCommand(JsonVariant contents, const Messa
|
||||
|
||||
// Note: If update succeeds, device will reboot and this won't be reached
|
||||
if (!result) {
|
||||
LOG_ERROR("Custom update failed");
|
||||
LOG_ERROR(TAG, "Custom update failed");
|
||||
// Error response may not be received if we already restarted
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
#include "CommunicationRouter.hpp"
|
||||
|
||||
#define TAG "CommRouter"
|
||||
#include "../../ConfigManager/ConfigManager.hpp"
|
||||
#include "../../OTAManager/OTAManager.hpp"
|
||||
#include "../../Networking/Networking.hpp"
|
||||
@@ -39,11 +41,11 @@ CommunicationRouter::CommunicationRouter(ConfigManager& configManager,
|
||||
CommunicationRouter::~CommunicationRouter() {}
|
||||
|
||||
void CommunicationRouter::begin() {
|
||||
LOG_INFO("Initializing Communication Router v4.0 (Modular)");
|
||||
LOG_INFO(TAG, "Initializing Communication Router v4.0 (Modular)");
|
||||
|
||||
// 🔥 CRITICAL: Initialize WebSocket FIRST to ensure it's always set up
|
||||
// Even if MQTT fails, we want WebSocket to work!
|
||||
LOG_INFO("Setting up WebSocket server...");
|
||||
LOG_INFO(TAG, "Setting up WebSocket server...");
|
||||
|
||||
// Initialize WebSocket server
|
||||
_wsServer.begin();
|
||||
@@ -54,11 +56,11 @@ void CommunicationRouter::begin() {
|
||||
// 🔥 CRITICAL FIX: Attach WebSocket handler to AsyncWebServer
|
||||
// This MUST happen before any potential failures!
|
||||
_server.addHandler(&_webSocket);
|
||||
LOG_INFO("✅ WebSocket handler attached to AsyncWebServer on /ws");
|
||||
LOG_INFO(TAG, "✅ WebSocket handler attached to AsyncWebServer on /ws");
|
||||
|
||||
//Now initialize MQTT client (can fail without breaking WebSocket)
|
||||
try {
|
||||
LOG_INFO("Setting up MQTT client...");
|
||||
LOG_INFO(TAG, "Setting up MQTT client...");
|
||||
_mqttClient.begin();
|
||||
_mqttClient.setCallback([this](const String& topic, const String& payload) {
|
||||
onMqttMessage(topic, payload);
|
||||
@@ -73,23 +75,36 @@ void CommunicationRouter::begin() {
|
||||
logTopic
|
||||
);
|
||||
|
||||
// Apply MQTT log level from config
|
||||
uint8_t mqttLogLevel = _configManager.getMqttLogLevel();
|
||||
Logging::setMqttLogLevel((Logging::LogLevel)mqttLogLevel);
|
||||
LOG_INFO("MQTT logging enabled with level %d on topic: %s", mqttLogLevel, logTopic.c_str());
|
||||
// Apply log levels from config for all three channels
|
||||
Logging::setSerialLevel((Logging::LogLevel)_configManager.getSerialLogLevel());
|
||||
Logging::setMqttLevel((Logging::LogLevel)_configManager.getMqttLogLevel());
|
||||
Logging::setSdLevel((Logging::LogLevel)_configManager.getSdLogLevel());
|
||||
LOG_INFO(TAG, "Log levels applied — Serial:%d MQTT:%d SD:%d",
|
||||
_configManager.getSerialLogLevel(),
|
||||
_configManager.getMqttLogLevel(),
|
||||
_configManager.getSdLogLevel());
|
||||
|
||||
LOG_INFO("✅ MQTT client initialized");
|
||||
// Silence MQTT-internal subsystems on the MQTT channel to prevent log storms.
|
||||
// These systems generate logs while sending logs — suppress them over MQTT only.
|
||||
Logging::setSubsystemMqttLevel("MQTTClient", Logging::NONE);
|
||||
Logging::setSubsystemMqttLevel("CommRouter", Logging::WARNING);
|
||||
Logging::setSubsystemMqttLevel("Logger", Logging::NONE);
|
||||
|
||||
LOG_INFO(TAG, "✅ MQTT client initialized");
|
||||
} catch (...) {
|
||||
LOG_ERROR("❌ MQTT initialization failed, but WebSocket is still available");
|
||||
LOG_ERROR(TAG, "❌ MQTT initialization failed, but WebSocket is still available");
|
||||
}
|
||||
|
||||
// Wire up SD logging channel (requires FileManager to be set first via setFileManagerReference)
|
||||
// SD callback is registered lazily in setFileManagerReference once the pointer is available
|
||||
|
||||
// 🔥 CRITICAL FIX: Connect ClientManager to CommandHandler
|
||||
_commandHandler.setClientManagerReference(&_clientManager);
|
||||
LOG_INFO("ClientManager reference set for CommandHandler");
|
||||
LOG_INFO(TAG, "ClientManager reference set for CommandHandler");
|
||||
|
||||
// 🔥 Set CommunicationRouter reference for MQTT control commands
|
||||
_commandHandler.setCommunicationRouterReference(this);
|
||||
LOG_INFO("CommunicationRouter reference set for CommandHandler");
|
||||
LOG_INFO(TAG, "CommunicationRouter reference set for CommandHandler");
|
||||
|
||||
// Setup command handler response callback
|
||||
_commandHandler.setResponseCallback([this](const String& response, const CommandHandler::MessageContext& context) {
|
||||
@@ -97,30 +112,30 @@ void CommunicationRouter::begin() {
|
||||
});
|
||||
|
||||
// Initialize HTTP Request Handler
|
||||
LOG_INFO("Setting up HTTP REST API...");
|
||||
LOG_INFO(TAG, "Setting up HTTP REST API...");
|
||||
_httpHandler.begin();
|
||||
_httpHandler.setCommandHandlerReference(&_commandHandler);
|
||||
LOG_INFO("✅ HTTP REST API initialized");
|
||||
LOG_INFO(TAG, "✅ HTTP REST API initialized");
|
||||
|
||||
// Initialize Settings Web Server
|
||||
LOG_INFO("Setting up Settings Web Server...");
|
||||
LOG_INFO(TAG, "Setting up Settings Web Server...");
|
||||
_settingsServer.begin();
|
||||
LOG_INFO("✅ Settings Web Server initialized at /settings");
|
||||
LOG_INFO(TAG, "✅ Settings Web Server initialized at /settings");
|
||||
|
||||
// Initialize UART Command Handler
|
||||
LOG_INFO("Setting up UART Command Handler...");
|
||||
LOG_INFO(TAG, "Setting up UART Command Handler...");
|
||||
_uartHandler.begin();
|
||||
_uartHandler.setCallback([this](JsonDocument& message) {
|
||||
onUartMessage(message);
|
||||
});
|
||||
LOG_INFO("✅ UART Command Handler initialized (TX: GPIO12, RX: GPIO13)");
|
||||
LOG_INFO(TAG, "✅ UART Command Handler initialized (TX: GPIO12, RX: GPIO13)");
|
||||
|
||||
LOG_INFO("Communication Router initialized with modular architecture");
|
||||
LOG_INFO(" • MQTT: AsyncMqttClient");
|
||||
LOG_INFO(" • WebSocket: Multi-client support");
|
||||
LOG_INFO(" • HTTP REST API: /api endpoints");
|
||||
LOG_INFO(" • UART: External device control");
|
||||
LOG_INFO(" • Settings Page: /settings");
|
||||
LOG_INFO(TAG, "Communication Router initialized with modular architecture");
|
||||
LOG_INFO(TAG, " • MQTT: AsyncMqttClient");
|
||||
LOG_INFO(TAG, " • WebSocket: Multi-client support");
|
||||
LOG_INFO(TAG, " • HTTP REST API: /api endpoints");
|
||||
LOG_INFO(TAG, " • UART: External device control");
|
||||
LOG_INFO(TAG, " • Settings Page: /settings");
|
||||
}
|
||||
|
||||
void CommunicationRouter::loop() {
|
||||
@@ -136,6 +151,14 @@ void CommunicationRouter::setPlayerReference(Player* player) {
|
||||
void CommunicationRouter::setFileManagerReference(FileManager* fm) {
|
||||
_fileManager = fm;
|
||||
_commandHandler.setFileManagerReference(fm);
|
||||
|
||||
// Register SD log channel now that FileManager is available
|
||||
if (fm != nullptr) {
|
||||
Logging::setSdWriteCallback([fm](const String& line) {
|
||||
fm->appendLine("/logs/vesper.log", line);
|
||||
});
|
||||
LOG_INFO(TAG, "SD log channel registered -> /logs/vesper.log");
|
||||
}
|
||||
}
|
||||
|
||||
void CommunicationRouter::setTimeKeeperReference(Timekeeper* tk) {
|
||||
@@ -155,11 +178,11 @@ void CommunicationRouter::setTelemetryReference(Telemetry* telemetry) {
|
||||
void CommunicationRouter::setupUdpDiscovery() {
|
||||
uint16_t discoveryPort = _configManager.getNetworkConfig().discoveryPort;
|
||||
if (_udp.listen(discoveryPort)) {
|
||||
LOG_INFO("UDP discovery listening on port %u", discoveryPort);
|
||||
LOG_INFO(TAG, "UDP discovery listening on port %u", discoveryPort);
|
||||
|
||||
_udp.onPacket([this](AsyncUDPPacket packet) {
|
||||
String msg = String((const char*)packet.data(), packet.length());
|
||||
LOG_DEBUG("UDP from %s:%u -> %s",
|
||||
LOG_DEBUG(TAG, "UDP from %s:%u -> %s",
|
||||
packet.remoteIP().toString().c_str(),
|
||||
packet.remotePort(),
|
||||
msg.c_str());
|
||||
@@ -200,7 +223,7 @@ void CommunicationRouter::setupUdpDiscovery() {
|
||||
packet.remoteIP(), packet.remotePort());
|
||||
});
|
||||
} else {
|
||||
LOG_ERROR("Failed to start UDP discovery.");
|
||||
LOG_ERROR(TAG, "Failed to start UDP discovery.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,22 +242,24 @@ size_t CommunicationRouter::getWebSocketClientCount() const {
|
||||
bool CommunicationRouter::isHealthy() const {
|
||||
// Check if required references are set
|
||||
if (!_player || !_fileManager || !_timeKeeper) {
|
||||
LOG_DEBUG("CommunicationRouter: Unhealthy - Missing references");
|
||||
LOG_WARNING(TAG, "Unhealthy - missing subsystem references (player=%d fileManager=%d timeKeeper=%d)",
|
||||
_player != nullptr, _fileManager != nullptr, _timeKeeper != nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Check network connectivity first — no point checking connections without a network
|
||||
if (!_networking.isConnected()) {
|
||||
LOG_WARNING(TAG, "Unhealthy - no network connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if at least one protocol is connected
|
||||
if (!isMqttConnected() && !hasActiveWebSocketClients()) {
|
||||
LOG_DEBUG("CommunicationRouter: Unhealthy - No active connections");
|
||||
LOG_WARNING(TAG, "Unhealthy - no active connections (MQTT=%d, WebSocket=%d)",
|
||||
isMqttConnected(), hasActiveWebSocketClients());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check network connectivity
|
||||
if (!_networking.isConnected()) {
|
||||
LOG_DEBUG("CommunicationRouter: Unhealthy - No network connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -270,9 +295,9 @@ void CommunicationRouter::broadcastToAllWebSocketClients(const JsonDocument& mes
|
||||
void CommunicationRouter::publishToMqtt(const String& data) {
|
||||
if (_mqttClient.isConnected()) {
|
||||
_mqttClient.publish("data", data, 0, false);
|
||||
LOG_DEBUG("Published to MQTT: %s", data.c_str());
|
||||
LOG_DEBUG(TAG, "Published to MQTT: %s", data.c_str());
|
||||
} else {
|
||||
LOG_ERROR("MQTT Not Connected! Message Failed: %s", data.c_str());
|
||||
LOG_ERROR(TAG, "MQTT Not Connected! Message Failed: %s", data.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,29 +319,29 @@ void CommunicationRouter::sendBellOverloadNotification(const std::vector<uint8_t
|
||||
overloadMsg["payload"]["severity"] = severity;
|
||||
broadcastStatus(overloadMsg);
|
||||
|
||||
LOG_WARNING("Bell overload notification sent: %d bells, severity: %s",
|
||||
LOG_WARNING(TAG, "Bell overload notification sent: %d bells, severity: %s",
|
||||
bellNumbers.size(), severity.c_str());
|
||||
}
|
||||
|
||||
void CommunicationRouter::onNetworkConnected() {
|
||||
LOG_DEBUG("Network connected - notifying MQTT client");
|
||||
LOG_DEBUG(TAG, "Network connected - notifying MQTT client");
|
||||
_mqttClient.onNetworkConnected();
|
||||
}
|
||||
|
||||
void CommunicationRouter::onNetworkDisconnected() {
|
||||
LOG_DEBUG("Network disconnected - notifying MQTT client");
|
||||
LOG_DEBUG(TAG, "Network disconnected - notifying MQTT client");
|
||||
_mqttClient.onNetworkDisconnected();
|
||||
}
|
||||
|
||||
void CommunicationRouter::onMqttMessage(const String& topic, const String& payload) {
|
||||
LOG_DEBUG("MQTT message received: %s", payload.c_str());
|
||||
LOG_DEBUG(TAG, "MQTT message received: %s", payload.c_str());
|
||||
|
||||
// Parse JSON
|
||||
StaticJsonDocument<2048> doc;
|
||||
DeserializationError error = deserializeJson(doc, payload);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse MQTT JSON: %s", error.c_str());
|
||||
LOG_ERROR(TAG, "Failed to parse MQTT JSON: %s", error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -330,7 +355,7 @@ void CommunicationRouter::onMqttMessage(const String& topic, const String& paylo
|
||||
void CommunicationRouter::onWebSocketMessage(uint32_t clientId, const JsonDocument& message) {
|
||||
// Extract command for logging
|
||||
String cmd = message["cmd"] | "unknown";
|
||||
LOG_INFO("📨 WebSocket message from client #%u: cmd=%s", clientId, cmd.c_str());
|
||||
LOG_INFO(TAG, "📨 WebSocket message from client #%u: cmd=%s", clientId, cmd.c_str());
|
||||
|
||||
// Create message context for WebSocket with client ID
|
||||
CommandHandler::MessageContext context(CommandHandler::MessageSource::WEBSOCKET, clientId);
|
||||
@@ -339,7 +364,7 @@ void CommunicationRouter::onWebSocketMessage(uint32_t clientId, const JsonDocume
|
||||
JsonDocument& mutableDoc = const_cast<JsonDocument&>(message);
|
||||
_commandHandler.processCommand(mutableDoc, context);
|
||||
|
||||
LOG_DEBUG("WebSocket message from client #%u processed", clientId);
|
||||
LOG_DEBUG(TAG, "WebSocket message from client #%u processed", clientId);
|
||||
}
|
||||
|
||||
void CommunicationRouter::onUartMessage(JsonDocument& message) {
|
||||
@@ -360,12 +385,12 @@ void CommunicationRouter::onUartMessage(JsonDocument& message) {
|
||||
|
||||
if (!allowed) {
|
||||
// Silently ignore - do NOT send error response to avoid feedback loop
|
||||
LOG_DEBUG("UART: Ignoring non-whitelisted command (cmd=%s, action=%s)",
|
||||
LOG_DEBUG(TAG, "UART: Ignoring non-whitelisted command (cmd=%s, action=%s)",
|
||||
cmd.c_str(), action.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("🔌 UART command received: cmd=%s, action=%s", cmd.c_str(), action.c_str());
|
||||
LOG_INFO(TAG, "🔌 UART command received: cmd=%s, action=%s", cmd.c_str(), action.c_str());
|
||||
|
||||
// Create message context for UART
|
||||
CommandHandler::MessageContext context(CommandHandler::MessageSource::UART);
|
||||
@@ -373,20 +398,20 @@ void CommunicationRouter::onUartMessage(JsonDocument& message) {
|
||||
// Forward to command handler
|
||||
_commandHandler.processCommand(message, context);
|
||||
|
||||
LOG_DEBUG("UART message processed");
|
||||
LOG_DEBUG(TAG, "UART message processed");
|
||||
}
|
||||
|
||||
void CommunicationRouter::sendResponse(const String& response, const CommandHandler::MessageContext& context) {
|
||||
if (context.source == CommandHandler::MessageSource::MQTT) {
|
||||
LOG_DEBUG("↗️ Sending response via MQTT: %s", response.c_str());
|
||||
LOG_DEBUG(TAG, "↗️ Sending response via MQTT: %s", response.c_str());
|
||||
publishToMqtt(response);
|
||||
} else if (context.source == CommandHandler::MessageSource::WEBSOCKET) {
|
||||
LOG_DEBUG("↗️ Sending response to WebSocket client #%u: %s", context.clientId, response.c_str());
|
||||
LOG_DEBUG(TAG, "↗️ Sending response to WebSocket client #%u: %s", context.clientId, response.c_str());
|
||||
_wsServer.sendToClient(context.clientId, response);
|
||||
} else if (context.source == CommandHandler::MessageSource::UART) {
|
||||
LOG_DEBUG("↗️ Sending response via UART: %s", response.c_str());
|
||||
LOG_DEBUG(TAG, "↗️ Sending response via UART: %s", response.c_str());
|
||||
_uartHandler.send(response);
|
||||
} else {
|
||||
LOG_ERROR("❌ Unknown message source for response routing!");
|
||||
LOG_ERROR(TAG, "❌ Unknown message source for response routing!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
#include "HTTPRequestHandler.hpp"
|
||||
|
||||
#define TAG "HTTPHandler"
|
||||
#include "../CommandHandler/CommandHandler.hpp"
|
||||
#include "../../ConfigManager/ConfigManager.hpp"
|
||||
#include "../../Logging/Logging.hpp"
|
||||
@@ -20,7 +22,7 @@ HTTPRequestHandler::~HTTPRequestHandler() {
|
||||
}
|
||||
|
||||
void HTTPRequestHandler::begin() {
|
||||
LOG_INFO("HTTPRequestHandler - Initializing HTTP REST API endpoints");
|
||||
LOG_INFO(TAG, "HTTPRequestHandler - Initializing HTTP REST API endpoints");
|
||||
|
||||
// POST /api/command - Execute any command
|
||||
_server.on("/api/command", HTTP_POST,
|
||||
@@ -61,15 +63,15 @@ void HTTPRequestHandler::begin() {
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Content-Type");
|
||||
|
||||
LOG_INFO("HTTPRequestHandler - REST API endpoints registered");
|
||||
LOG_INFO(" POST /api/command - Execute commands");
|
||||
LOG_INFO(" GET /api/status - System status");
|
||||
LOG_INFO(" GET /api/ping - Health check");
|
||||
LOG_INFO(TAG, "HTTPRequestHandler - REST API endpoints registered");
|
||||
LOG_INFO(TAG, " POST /api/command - Execute commands");
|
||||
LOG_INFO(TAG, " GET /api/status - System status");
|
||||
LOG_INFO(TAG, " GET /api/ping - Health check");
|
||||
}
|
||||
|
||||
void HTTPRequestHandler::setCommandHandlerReference(CommandHandler* handler) {
|
||||
_commandHandler = handler;
|
||||
LOG_DEBUG("HTTPRequestHandler - CommandHandler reference set");
|
||||
LOG_DEBUG(TAG, "HTTPRequestHandler - CommandHandler reference set");
|
||||
}
|
||||
|
||||
bool HTTPRequestHandler::isHealthy() const {
|
||||
@@ -88,12 +90,12 @@ void HTTPRequestHandler::handleCommandRequest(AsyncWebServerRequest* request, ui
|
||||
DeserializationError error = deserializeJson(doc, data, len);
|
||||
|
||||
if (error) {
|
||||
LOG_WARNING("HTTPRequestHandler - JSON parse error: %s", error.c_str());
|
||||
LOG_WARNING(TAG, "HTTPRequestHandler - JSON parse error: %s", error.c_str());
|
||||
sendErrorResponse(request, 400, "Invalid JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("HTTPRequestHandler - Processing command via HTTP");
|
||||
LOG_DEBUG(TAG, "HTTPRequestHandler - Processing command via HTTP");
|
||||
|
||||
// Create message context for HTTP (treat as WebSocket with special ID)
|
||||
CommandHandler::MessageContext context(CommandHandler::MessageSource::WEBSOCKET, 0xFFFFFFFF);
|
||||
@@ -129,7 +131,7 @@ void HTTPRequestHandler::handleStatusRequest(AsyncWebServerRequest* request) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("HTTPRequestHandler - Status request via HTTP");
|
||||
LOG_DEBUG(TAG, "HTTPRequestHandler - Status request via HTTP");
|
||||
|
||||
// Create a status command
|
||||
JsonDocument doc;
|
||||
@@ -160,7 +162,7 @@ void HTTPRequestHandler::handleStatusRequest(AsyncWebServerRequest* request) {
|
||||
}
|
||||
|
||||
void HTTPRequestHandler::handlePingRequest(AsyncWebServerRequest* request) {
|
||||
LOG_DEBUG("HTTPRequestHandler - Ping request via HTTP");
|
||||
LOG_DEBUG(TAG, "HTTPRequestHandler - Ping request via HTTP");
|
||||
|
||||
JsonDocument response;
|
||||
response["status"] = "ok";
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
#include "MQTTAsyncClient.hpp"
|
||||
|
||||
#define TAG "MQTTClient"
|
||||
#include "../../ConfigManager/ConfigManager.hpp"
|
||||
#include "../../Networking/Networking.hpp"
|
||||
#include "../../Logging/Logging.hpp"
|
||||
@@ -66,7 +68,7 @@ MQTTAsyncClient::~MQTTAsyncClient() {
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::begin() {
|
||||
LOG_INFO("Initializing MQTT Async Client");
|
||||
LOG_INFO(TAG, "Initializing MQTT Async Client");
|
||||
|
||||
auto& mqttConfig = _configManager.getMqttConfig();
|
||||
|
||||
@@ -76,7 +78,7 @@ void MQTTAsyncClient::begin() {
|
||||
_dataTopic = "vesper/" + deviceUID + "/data";
|
||||
_clientId = "vesper-" + deviceUID;
|
||||
|
||||
LOG_INFO("MQTT Topics: control=%s, data=%s", _controlTopic.c_str(), _dataTopic.c_str());
|
||||
LOG_INFO(TAG, "MQTT Topics: control=%s, data=%s", _controlTopic.c_str(), _dataTopic.c_str());
|
||||
|
||||
// Setup event handlers
|
||||
_mqttClient.onConnect([this](bool sessionPresent) {
|
||||
@@ -110,7 +112,7 @@ void MQTTAsyncClient::begin() {
|
||||
_mqttClient.setKeepAlive(15);
|
||||
_mqttClient.setCleanSession(true);
|
||||
|
||||
LOG_INFO("✅ MQTT Async Client initialized");
|
||||
LOG_INFO(TAG, "✅ MQTT Async Client initialized");
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::connect() {
|
||||
@@ -118,28 +120,28 @@ void MQTTAsyncClient::connect() {
|
||||
|
||||
// 🔥 Check if MQTT is enabled
|
||||
if (!mqttConfig.enabled) {
|
||||
LOG_DEBUG("MQTT is disabled in configuration - skipping connection");
|
||||
LOG_DEBUG(TAG, "MQTT is disabled in configuration - skipping connection");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mqttClient.connected()) {
|
||||
LOG_DEBUG("Already connected to MQTT");
|
||||
LOG_DEBUG(TAG, "Already connected to MQTT");
|
||||
return;
|
||||
}
|
||||
|
||||
// Track connection attempt
|
||||
_lastConnectionAttempt = millis();
|
||||
|
||||
LOG_INFO("Free heap BEFORE MQTT connect: %d bytes", ESP.getFreeHeap());
|
||||
LOG_INFO(TAG, "Free heap BEFORE MQTT connect: %d bytes", ESP.getFreeHeap());
|
||||
|
||||
_mqttClient.connect();
|
||||
|
||||
LOG_INFO("MQTT connect() called - waiting for async connection...");
|
||||
LOG_INFO(TAG, "MQTT connect() called - waiting for async connection...");
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::disconnect() {
|
||||
_mqttClient.disconnect();
|
||||
LOG_INFO("Disconnected from MQTT broker");
|
||||
LOG_INFO(TAG, "Disconnected from MQTT broker");
|
||||
}
|
||||
|
||||
uint16_t MQTTAsyncClient::publish(const String& topic, const String& payload, int qos, bool retain) {
|
||||
@@ -155,7 +157,7 @@ uint16_t MQTTAsyncClient::publish(const String& topic, const String& payload, in
|
||||
uint16_t packetId = _mqttClient.publish(fullTopic.c_str(), qos, retain, payload.c_str());
|
||||
|
||||
if (packetId > 0) {
|
||||
LOG_DEBUG("Published to %s: %s (packetId=%d)", fullTopic.c_str(), payload.c_str(), packetId);
|
||||
LOG_DEBUG(TAG, "Published to %s: %s (packetId=%d)", fullTopic.c_str(), payload.c_str(), packetId);
|
||||
}
|
||||
// REMOVED: Error logging here to prevent infinite recursion with MQTT logs
|
||||
|
||||
@@ -175,11 +177,11 @@ void MQTTAsyncClient::onNetworkConnected() {
|
||||
|
||||
// 🔥 Only attempt connection if MQTT is enabled
|
||||
if (!mqttConfig.enabled) {
|
||||
LOG_DEBUG("Network connected but MQTT is disabled - skipping MQTT connection");
|
||||
LOG_DEBUG(TAG, "Network connected but MQTT is disabled - skipping MQTT connection");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Network connected - scheduling MQTT connection after 2s stabilization (non-blocking)");
|
||||
LOG_DEBUG(TAG, "Network connected - scheduling MQTT connection after 2s stabilization (non-blocking)");
|
||||
|
||||
// Reset reconnect attempts on fresh network connection
|
||||
_reconnectAttempts = 0;
|
||||
@@ -189,14 +191,14 @@ void MQTTAsyncClient::onNetworkConnected() {
|
||||
if (_networkStabilizationTimer) {
|
||||
xTimerStart(_networkStabilizationTimer, 0);
|
||||
} else {
|
||||
LOG_ERROR("Network stabilization timer not initialized!");
|
||||
LOG_ERROR(TAG, "Network stabilization timer not initialized!");
|
||||
// Fallback to immediate connection (better than blocking)
|
||||
connect();
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onNetworkDisconnected() {
|
||||
LOG_DEBUG("Network disconnected - MQTT will auto-reconnect when network returns");
|
||||
LOG_DEBUG(TAG, "Network disconnected - MQTT will auto-reconnect when network returns");
|
||||
|
||||
if (_mqttClient.connected()) {
|
||||
_mqttClient.disconnect(true);
|
||||
@@ -205,12 +207,12 @@ void MQTTAsyncClient::onNetworkDisconnected() {
|
||||
|
||||
void MQTTAsyncClient::subscribe() {
|
||||
uint16_t packetId = _mqttClient.subscribe(_controlTopic.c_str(), 0);
|
||||
LOG_INFO("📬 Subscribing to control topic: %s (packetId=%d)", _controlTopic.c_str(), packetId);
|
||||
LOG_INFO(TAG, "📬 Subscribing to control topic: %s (packetId=%d)", _controlTopic.c_str(), packetId);
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onMqttConnect(bool sessionPresent) {
|
||||
LOG_INFO("✅ Connected to MQTT broker (session present: %s)", sessionPresent ? "yes" : "no");
|
||||
LOG_INFO("🔍 Free heap AFTER MQTT connect: %d bytes", ESP.getFreeHeap());
|
||||
LOG_INFO(TAG, "✅ Connected to MQTT broker (session present: %s)", sessionPresent ? "yes" : "no");
|
||||
LOG_INFO(TAG, "🔍 Free heap AFTER MQTT connect: %d bytes", ESP.getFreeHeap());
|
||||
|
||||
// Reset reconnection attempts on successful connection
|
||||
_reconnectAttempts = 0;
|
||||
@@ -250,14 +252,14 @@ void MQTTAsyncClient::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_ERROR("❌ Disconnected from MQTT broker - Reason: %s (%d)", reasonStr, static_cast<int>(reason));
|
||||
LOG_ERROR(TAG, "❌ Disconnected from MQTT broker - Reason: %s (%d)", reasonStr, static_cast<int>(reason));
|
||||
|
||||
// Stop heartbeat timer when disconnected
|
||||
stopHeartbeat();
|
||||
|
||||
// 🔥 Don't attempt reconnection if MQTT is disabled
|
||||
if (!mqttConfig.enabled) {
|
||||
LOG_INFO("MQTT is disabled - not attempting reconnection");
|
||||
LOG_INFO(TAG, "MQTT is disabled - not attempting reconnection");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -268,24 +270,24 @@ void MQTTAsyncClient::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||
// Calculate backoff delay
|
||||
unsigned long reconnectDelay = getReconnectDelay();
|
||||
|
||||
LOG_INFO("Network still connected - scheduling MQTT reconnection #%d in %lu seconds (backoff active)",
|
||||
LOG_INFO(TAG, "Network still connected - scheduling MQTT reconnection #%d in %lu seconds (backoff active)",
|
||||
_reconnectAttempts, reconnectDelay / 1000);
|
||||
|
||||
// Update timer period with new delay
|
||||
xTimerChangePeriod(_mqttReconnectTimer, pdMS_TO_TICKS(reconnectDelay), 0);
|
||||
xTimerStart(_mqttReconnectTimer, 0);
|
||||
} else {
|
||||
LOG_INFO("Network is down - waiting for network to reconnect");
|
||||
LOG_INFO(TAG, "Network is down - waiting for network to reconnect");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onMqttSubscribe(uint16_t packetId, uint8_t qos) {
|
||||
LOG_INFO("✅ Subscribed to topic (packetId=%d, QoS=%d)", packetId, qos);
|
||||
LOG_INFO(TAG, "✅ Subscribed to topic (packetId=%d, QoS=%d)", packetId, qos);
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onMqttUnsubscribe(uint16_t packetId) {
|
||||
LOG_DEBUG("Unsubscribed from topic (packetId=%d)", packetId);
|
||||
LOG_DEBUG(TAG, "Unsubscribed from topic (packetId=%d)", packetId);
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
@@ -293,7 +295,7 @@ void MQTTAsyncClient::onMqttMessage(char* topic, char* payload, AsyncMqttClientM
|
||||
String topicStr = String(topic);
|
||||
String payloadStr = String(payload).substring(0, len);
|
||||
|
||||
LOG_DEBUG("MQTT message received - topic: %s, payload: %s", topicStr.c_str(), payloadStr.c_str());
|
||||
LOG_DEBUG(TAG, "MQTT message received - topic: %s, payload: %s", topicStr.c_str(), payloadStr.c_str());
|
||||
|
||||
// Call user callback
|
||||
if (_messageCallback) {
|
||||
@@ -302,16 +304,16 @@ void MQTTAsyncClient::onMqttMessage(char* topic, char* payload, AsyncMqttClientM
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::onMqttPublish(uint16_t packetId) {
|
||||
LOG_DEBUG("MQTT publish acknowledged (packetId=%d)", packetId);
|
||||
LOG_DEBUG(TAG, "MQTT publish acknowledged (packetId=%d)", packetId);
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::attemptReconnection() {
|
||||
// Double-check network is still up
|
||||
if (_networking.isConnected()) {
|
||||
LOG_INFO("Attempting MQTT reconnection...");
|
||||
LOG_INFO(TAG, "Attempting MQTT reconnection...");
|
||||
connect();
|
||||
} else {
|
||||
LOG_WARNING("Network down during reconnect attempt - aborting");
|
||||
LOG_WARNING(TAG, "Network down during reconnect attempt - aborting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +333,7 @@ void MQTTAsyncClient::mqttReconnectTimerCallback(TimerHandle_t xTimer) {
|
||||
|
||||
void MQTTAsyncClient::startHeartbeat() {
|
||||
if (_heartbeatTimer) {
|
||||
LOG_INFO("💓 Starting MQTT heartbeat (every %d seconds)", HEARTBEAT_INTERVAL / 1000);
|
||||
LOG_INFO(TAG, "💓 Starting MQTT heartbeat (every %d seconds)", HEARTBEAT_INTERVAL / 1000);
|
||||
|
||||
// Publish first heartbeat immediately
|
||||
publishHeartbeat();
|
||||
@@ -344,13 +346,13 @@ void MQTTAsyncClient::startHeartbeat() {
|
||||
void MQTTAsyncClient::stopHeartbeat() {
|
||||
if (_heartbeatTimer) {
|
||||
xTimerStop(_heartbeatTimer, 0);
|
||||
LOG_INFO("❤️ Stopped MQTT heartbeat");
|
||||
LOG_INFO(TAG, "❤️ Stopped MQTT heartbeat");
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTAsyncClient::publishHeartbeat() {
|
||||
if (!_mqttClient.connected()) {
|
||||
LOG_WARNING("⚠️ Cannot publish heartbeat - MQTT not connected");
|
||||
LOG_WARNING(TAG, "⚠️ Cannot publish heartbeat - MQTT not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -397,10 +399,10 @@ void MQTTAsyncClient::publishHeartbeat() {
|
||||
uint16_t packetId = _mqttClient.publish(heartbeatTopic.c_str(), 1, true, heartbeatMessage.c_str());
|
||||
|
||||
if (packetId > 0) {
|
||||
LOG_DEBUG("💓 Published heartbeat (retained) - IP: %s, Uptime: %lums",
|
||||
LOG_DEBUG(TAG, "💓 Published heartbeat (retained) - IP: %s, Uptime: %lums",
|
||||
_networking.getLocalIP().c_str(), uptimeMs);
|
||||
} else {
|
||||
LOG_ERROR("❌ Failed to publish heartbeat");
|
||||
LOG_ERROR(TAG, "❌ Failed to publish heartbeat");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +417,7 @@ void MQTTAsyncClient::heartbeatTimerCallback(TimerHandle_t xTimer) {
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
void MQTTAsyncClient::connectAfterStabilization() {
|
||||
LOG_DEBUG("Network stabilization complete - connecting to MQTT");
|
||||
LOG_DEBUG(TAG, "Network stabilization complete - connecting to MQTT");
|
||||
connect();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "ResponseBuilder.hpp"
|
||||
|
||||
#define TAG "ResponseBuilder"
|
||||
#include "../../Logging/Logging.hpp"
|
||||
|
||||
// Static member initialization
|
||||
@@ -72,7 +74,7 @@ String ResponseBuilder::deviceStatus(PlayerStatus playerStatus, uint32_t timeEla
|
||||
String result;
|
||||
serializeJson(statusDoc, result);
|
||||
|
||||
LOG_DEBUG("Device status response: %s", result.c_str());
|
||||
LOG_DEBUG(TAG, "Device status response: %s", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -135,7 +137,7 @@ String ResponseBuilder::buildResponse(Status status, const String& type, const S
|
||||
String result;
|
||||
serializeJson(_responseDoc, result);
|
||||
|
||||
LOG_DEBUG("Response built: %s", result.c_str());
|
||||
LOG_DEBUG(TAG, "Response built: %s", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -149,7 +151,7 @@ String ResponseBuilder::buildResponse(Status status, const String& type, const J
|
||||
String result;
|
||||
serializeJson(_responseDoc, result);
|
||||
|
||||
LOG_DEBUG("Response built: %s", result.c_str());
|
||||
LOG_DEBUG(TAG, "Response built: %s", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
#include "UARTCommandHandler.hpp"
|
||||
|
||||
#define TAG "UARTHandler"
|
||||
#include "../../Logging/Logging.hpp"
|
||||
|
||||
UARTCommandHandler::UARTCommandHandler(uint8_t txPin, uint8_t rxPin, uint32_t baudRate)
|
||||
@@ -24,10 +26,10 @@ UARTCommandHandler::~UARTCommandHandler() {
|
||||
}
|
||||
|
||||
void UARTCommandHandler::begin() {
|
||||
LOG_INFO("Initializing UART Command Handler");
|
||||
LOG_INFO(" TX Pin: GPIO%d", _txPin);
|
||||
LOG_INFO(" RX Pin: GPIO%d", _rxPin);
|
||||
LOG_INFO(" Baud Rate: %u", _baudRate);
|
||||
LOG_INFO(TAG, "Initializing UART Command Handler");
|
||||
LOG_INFO(TAG, " TX Pin: GPIO%d", _txPin);
|
||||
LOG_INFO(TAG, " RX Pin: GPIO%d", _rxPin);
|
||||
LOG_INFO(TAG, " Baud Rate: %u", _baudRate);
|
||||
|
||||
// Initialize Serial2 with custom pins
|
||||
_serial.begin(_baudRate, SERIAL_8N1, _rxPin, _txPin);
|
||||
@@ -38,7 +40,7 @@ void UARTCommandHandler::begin() {
|
||||
}
|
||||
|
||||
_ready = true;
|
||||
LOG_INFO("UART Command Handler ready");
|
||||
LOG_INFO(TAG, "UART Command Handler ready");
|
||||
}
|
||||
|
||||
void UARTCommandHandler::loop() {
|
||||
@@ -65,7 +67,7 @@ void UARTCommandHandler::loop() {
|
||||
_buffer[_bufferIndex++] = c;
|
||||
} else {
|
||||
// Buffer overflow - discard and reset
|
||||
LOG_ERROR("UART buffer overflow, discarding message");
|
||||
LOG_ERROR(TAG, "UART buffer overflow, discarding message");
|
||||
_errorCount++;
|
||||
resetBuffer();
|
||||
}
|
||||
@@ -78,7 +80,7 @@ void UARTCommandHandler::setCallback(MessageCallback callback) {
|
||||
|
||||
void UARTCommandHandler::send(const String& response) {
|
||||
if (!_ready) {
|
||||
LOG_ERROR("UART not ready, cannot send response");
|
||||
LOG_ERROR(TAG, "UART not ready, cannot send response");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -86,11 +88,11 @@ void UARTCommandHandler::send(const String& response) {
|
||||
_serial.print('\n'); // Newline delimiter
|
||||
_serial.flush(); // Ensure data is sent
|
||||
|
||||
LOG_DEBUG("UART TX: %s", response.c_str());
|
||||
LOG_DEBUG(TAG, "UART TX: %s", response.c_str());
|
||||
}
|
||||
|
||||
void UARTCommandHandler::processLine(const char* line) {
|
||||
LOG_DEBUG("UART RX: %s", line);
|
||||
LOG_DEBUG(TAG, "UART RX: %s", line);
|
||||
|
||||
// Skip empty lines or whitespace-only
|
||||
if (strlen(line) == 0) return;
|
||||
@@ -100,7 +102,7 @@ void UARTCommandHandler::processLine(const char* line) {
|
||||
DeserializationError error = deserializeJson(doc, line);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("UART JSON parse error: %s", error.c_str());
|
||||
LOG_ERROR(TAG, "UART JSON parse error: %s", error.c_str());
|
||||
_errorCount++;
|
||||
|
||||
// Send error response back
|
||||
@@ -121,7 +123,7 @@ void UARTCommandHandler::processLine(const char* line) {
|
||||
if (_callback) {
|
||||
_callback(doc);
|
||||
} else {
|
||||
LOG_WARNING("UART message received but no callback set");
|
||||
LOG_WARNING(TAG, "UART message received but no callback set");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
#include "WebSocketServer.hpp"
|
||||
|
||||
#define TAG "WebSocket"
|
||||
#include "../../Logging/Logging.hpp"
|
||||
#include "../ResponseBuilder/ResponseBuilder.hpp"
|
||||
|
||||
@@ -23,7 +25,7 @@ WebSocketServer::~WebSocketServer() {
|
||||
|
||||
void WebSocketServer::begin() {
|
||||
_webSocket.onEvent(onEvent);
|
||||
LOG_INFO("WebSocket server initialized on /ws");
|
||||
LOG_INFO(TAG, "WebSocket server initialized on /ws");
|
||||
|
||||
// 🔥 CRITICAL: This line was missing - attach WebSocket to the AsyncWebServer
|
||||
// Without this, the server doesn't know about the WebSocket handler!
|
||||
@@ -40,17 +42,17 @@ void WebSocketServer::sendToClient(uint32_t clientId, const String& message) {
|
||||
|
||||
void WebSocketServer::broadcastToAll(const String& message) {
|
||||
_clientManager.broadcastToAll(message);
|
||||
LOG_DEBUG("Broadcast to all WebSocket clients: %s", message.c_str());
|
||||
LOG_DEBUG(TAG, "Broadcast to all WebSocket clients: %s", message.c_str());
|
||||
}
|
||||
|
||||
void WebSocketServer::broadcastToMaster(const String& message) {
|
||||
_clientManager.sendToMasterClients(message);
|
||||
LOG_DEBUG("Broadcast to master clients: %s", message.c_str());
|
||||
LOG_DEBUG(TAG, "Broadcast to master clients: %s", message.c_str());
|
||||
}
|
||||
|
||||
void WebSocketServer::broadcastToSecondary(const String& message) {
|
||||
_clientManager.sendToSecondaryClients(message);
|
||||
LOG_DEBUG("Broadcast to secondary clients: %s", message.c_str());
|
||||
LOG_DEBUG(TAG, "Broadcast to secondary clients: %s", message.c_str());
|
||||
}
|
||||
|
||||
bool WebSocketServer::hasClients() const {
|
||||
@@ -64,7 +66,7 @@ size_t WebSocketServer::getClientCount() const {
|
||||
void WebSocketServer::onEvent(AsyncWebSocket* server, AsyncWebSocketClient* client,
|
||||
AwsEventType type, void* arg, uint8_t* data, size_t len) {
|
||||
if (!_instance) {
|
||||
LOG_ERROR("WebSocketServer static instance is NULL - callback ignored!");
|
||||
LOG_ERROR(TAG, "WebSocketServer static instance is NULL - callback ignored!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,7 +84,7 @@ void WebSocketServer::onEvent(AsyncWebSocket* server, AsyncWebSocketClient* clie
|
||||
break;
|
||||
|
||||
case WS_EVT_ERROR:
|
||||
LOG_ERROR("WebSocket client #%u error(%u): %s",
|
||||
LOG_ERROR(TAG, "WebSocket client #%u error(%u): %s",
|
||||
client->id(), *((uint16_t*)arg), (char*)data);
|
||||
break;
|
||||
|
||||
@@ -92,7 +94,7 @@ void WebSocketServer::onEvent(AsyncWebSocket* server, AsyncWebSocketClient* clie
|
||||
}
|
||||
|
||||
void WebSocketServer::onConnect(AsyncWebSocketClient* client) {
|
||||
LOG_INFO("WebSocket client #%u connected from %s",
|
||||
LOG_INFO(TAG, "WebSocket client #%u connected from %s",
|
||||
client->id(), client->remoteIP().toString().c_str());
|
||||
|
||||
// Add client to manager (type UNKNOWN until they identify)
|
||||
@@ -104,7 +106,7 @@ void WebSocketServer::onConnect(AsyncWebSocketClient* client) {
|
||||
}
|
||||
|
||||
void WebSocketServer::onDisconnect(AsyncWebSocketClient* client) {
|
||||
LOG_INFO("WebSocket client #%u disconnected", client->id());
|
||||
LOG_INFO(TAG, "WebSocket client #%u disconnected", client->id());
|
||||
|
||||
_clientManager.removeClient(client->id());
|
||||
_clientManager.cleanupDisconnectedClients();
|
||||
@@ -118,7 +120,7 @@ void WebSocketServer::onData(AsyncWebSocketClient* client, void* arg, uint8_t* d
|
||||
// Allocate buffer for payload
|
||||
char* payload = (char*)malloc(len + 1);
|
||||
if (!payload) {
|
||||
LOG_ERROR("Failed to allocate memory for WebSocket payload");
|
||||
LOG_ERROR(TAG, "Failed to allocate memory for WebSocket payload");
|
||||
String errorResponse = ResponseBuilder::error("memory_error", "Out of memory");
|
||||
_clientManager.sendToClient(client->id(), errorResponse);
|
||||
return;
|
||||
@@ -127,14 +129,14 @@ void WebSocketServer::onData(AsyncWebSocketClient* client, void* arg, uint8_t* d
|
||||
memcpy(payload, data, len);
|
||||
payload[len] = '\0';
|
||||
|
||||
LOG_DEBUG("WebSocket client #%u sent: %s", client->id(), payload);
|
||||
LOG_DEBUG(TAG, "WebSocket client #%u sent: %s", client->id(), payload);
|
||||
|
||||
// Parse JSON
|
||||
StaticJsonDocument<2048> doc;
|
||||
DeserializationError error = deserializeJson(doc, payload);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse WebSocket JSON from client #%u: %s", client->id(), error.c_str());
|
||||
LOG_ERROR(TAG, "Failed to parse WebSocket JSON from client #%u: %s", client->id(), error.c_str());
|
||||
String errorResponse = ResponseBuilder::error("parse_error", "Invalid JSON");
|
||||
_clientManager.sendToClient(client->id(), errorResponse);
|
||||
} else {
|
||||
@@ -143,15 +145,15 @@ void WebSocketServer::onData(AsyncWebSocketClient* client, void* arg, uint8_t* d
|
||||
|
||||
// Call user callback if set
|
||||
if (_messageCallback) {
|
||||
LOG_DEBUG("Routing message from client #%u to callback handler", client->id());
|
||||
LOG_DEBUG(TAG, "Routing message from client #%u to callback handler", client->id());
|
||||
_messageCallback(client->id(), doc);
|
||||
} else {
|
||||
LOG_WARNING("WebSocket message received but no callback handler is set!");
|
||||
LOG_WARNING(TAG, "WebSocket message received but no callback handler is set!");
|
||||
}
|
||||
}
|
||||
|
||||
free(payload);
|
||||
} else {
|
||||
LOG_WARNING("Received fragmented or non-text WebSocket message from client #%u - ignoring", client->id());
|
||||
LOG_WARNING(TAG, "Received fragmented or non-text WebSocket message from client #%u - ignoring", client->id());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user