Перенаправление сообщений ESP_LOGx через WebSocket
Добавил(а) microsin
В более новых версиях ESP-IDF (v5.0 и выше) компонент esp_websocket_client больше не входит в состав фреймворка по умолчанию. Он был вынесен в отдельный репозиторий esp-protocols и теперь устанавливается как внешний компонент.
Вы можете склонировать репозиторий в папку components вашего проекта:
cd components git clone https://github.com/espressif/esp-protocols.git
Затем используйте компонент из папки esp-protocols/components/esp_websocket_client.
[Важные замечания]
1. Требования к версии IDF: компонент esp_websocket_client требует ESP-IDF версии 5.0 или выше. 2. Зависимости: компонент автоматически подтягивает необходимые зависимости, включая http_parser.
Если вы не хотите использовать внешний компонент, вы можете реализовать отправку логов через обычные TCP сокеты или использовать библиотеку libwebsockets, которая также доступна как компонент.
// Настройки #define UMSG_LOG_QUEUE_SIZE 100 // Размер очереди сообщений #define UMSG_LOG_MAX_MSG_LEN 512 // Максимальная длина сообщения #define UMSG_LOG_TASK_STACK 4096 // Размер стека задачи #define UMSG_LOG_TASK_PRIORITY 5 // Приоритет задачи
// Структура сообщения для очереди typedefstruct{ charmessage[UMSG_LOG_MAX_MSG_LEN]; umsg_log_level_tlevel; chartag[32];
}umsg_log_message_t;
// Структура конфигурации логгера typedefstruct{ esp_websocket_client_handle_tws_client; booluart_output_enabled;// Выводить ли также в UART boolcolor_enabled;// Использовать ли цвета
}umsg_log_config_t;
// Отправка лога через WebSocket (внутренняя функция) voidumsg_log_send(constchar*tag,umsg_log_level_tlevel,constchar*format,...);
// Получение строкового представления уровня лога constchar*umsg_log_level_to_string(umsg_log_level_tlevel);
// Макросы с таким же интерфейсом как у ESP_LOGx #define UMSGI(tag, format, ...) \ do { \ umsg_log_send(tag, UMSG_LOG_INFO, format, ##__VA_ARGS__); \ } while(0)
#define UMSGW(tag, format, ...) \ do { \ umsg_log_send(tag, UMSG_LOG_WARN, format, ##__VA_ARGS__); \ } while(0)
#define UMSGE(tag, format, ...) \ do { \ umsg_log_send(tag, UMSG_LOG_ERROR, format, ##__VA_ARGS__); \ } while(0)
// Макросы с условием (аналог ESP_LOGI_IS_ENABLED) #define UMSGI_IS_ENABLED(level) 1 // Всегда включены #define UMSGW_IS_ENABLED(level) 1 #define UMSGE_IS_ENABLED(level) 1
// Макросы с проверкой уровня (аналог ESP_LOG_LEVEL_LOCAL) #define UMSG_LOG_LEVEL_LOCAL ESP_LOG_VERBOSE #define UMSG_LOG_LEVEL(tag, level, format, ...) \ do { \ if (level >= UMSG_LOG_LEVEL_LOCAL) { \ umsg_log_send(tag, level, format, ##__VA_ARGS__); \ } \ } while(0)
#ifdef __cplusplus
} #endif
#endif // UMSG_LOG_H
Код модуля main/umsg_log.c, где используется подключение WebSocket клиента:
// Получение строкового представления уровня лога constchar*umsg_log_level_to_string(umsg_log_level_tlevel){ switch(level){ caseUMSG_LOG_INFO:return"I"; caseUMSG_LOG_WARN:return"W"; caseUMSG_LOG_ERROR:return"E"; default:return"?"; }
}
// Форматирование сообщения для WebSocket staticvoidformat_websocket_message(char*buffer,size_tbuffer_size, constchar*tag,umsg_log_level_tlevel, constchar*message){ uint32_ttimestamp_ms=esp_timer_get_time()/1000;
// Форматирование сообщения для UART staticvoidformat_uart_message(char*buffer,size_tbuffer_size, constchar*tag,umsg_log_level_tlevel, constchar*message){ constchar*color=get_color_for_level(level); constchar*level_str=umsg_log_level_to_string(level);
// Задача для отправки логов через WebSocket staticvoidumsg_log_task(void*pvParameters){ umsg_log_message_tlog_msg;
while(1){ if(xQueueReceive(umsg_log_queue,&log_msg,portMAX_DELAY)==pdTRUE){ // Форматируем сообщение для WebSocket charws_buffer[UMSG_LOG_MAX_MSG_LEN+128]; format_websocket_message(ws_buffer,sizeof(ws_buffer), log_msg.tag,log_msg.level,log_msg.message);
// Выводим в UART если нужно if(umsg_log_config.uart_output_enabled){ charuart_buffer[UMSG_LOG_MAX_MSG_LEN+128]; format_uart_message(uart_buffer,sizeof(uart_buffer), log_msg.tag,log_msg.level,log_msg.message); printf("%s",uart_buffer); } } }
}
// Внутренняя функция отправки лога staticvoidumsg_log_vprintf(constchar*tag,umsg_log_level_tlevel, constchar*format,va_listargs){ if(umsg_log_queue==NULL)return;
// Опционально: отключить вывод в UART (если нужно только WebSocket) // umsg_log_set_uart_output(false);
// Использование макросов (интерфейс как у ESP_LOGI) UMSGI("MAIN","Application started"); UMSGW("MAIN","Warning: low memory"); UMSGE("MAIN","Error: connection failed");
// Форматированные сообщения intvalue=42; UMSGI("TAG","Value = %d, string = %s",value,"test");
// В любой момент можно отправить лог umsg_log_send("CUSTOM",UMSG_LOG_INFO,"Custom message");
// ... остальной код ...
// При завершении umsg_log_deinit();
}
Формат сообщения для WebSocket. Сообщения отправляются в JSON формате, так их проще декодировать и анализировать на принимающей стороне:
level: I (Info), W (Warning), E (Error) tag: текстовый тег сообщения message: текст сообщения timestamp: время в миллисекундах core: номер ядра ESP32 (0 или 1)
Преимущества такого подхода:
● Совместимость: Интерфейс идентичен ESP_LOGx макросам. ● Асинхронность: Используется очередь и отдельная задача, не блокирует основной код. ● Гибкость: Можно одновременно выводить и в UART, и в WebSocket. ● Надежность: Очередь предотвращает потерю сообщений при временных проблемах с WebSocket. ● Расширяемость: Легко добавить дополнительные форматы вывода (SD card, MQTT и т.д.)
Теперь вы можете использовать UMSGI, UMSGW, UMSGE точно так же, как стандартные макросы ESP-IDF, но ваши сообщения будут отправляться через WebSocket.