mirror of
https://github.com/esphome/esphome.git
synced 2025-10-03 10:32:21 +01:00
Merge branch 'dev' into client_info_flash
This commit is contained in:
@@ -36,29 +36,31 @@ struct device;
|
|||||||
|
|
||||||
namespace esphome::logger {
|
namespace esphome::logger {
|
||||||
|
|
||||||
// Color and letter constants for log levels
|
// ANSI color code last digit (30-38 range, store only last digit to save RAM)
|
||||||
static const char *const LOG_LEVEL_COLORS[] = {
|
static constexpr char LOG_LEVEL_COLOR_DIGIT[] = {
|
||||||
"", // NONE
|
'\0', // NONE
|
||||||
ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), // ERROR
|
'1', // ERROR (31 = red)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_YELLOW), // WARNING
|
'3', // WARNING (33 = yellow)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GREEN), // INFO
|
'2', // INFO (32 = green)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_MAGENTA), // CONFIG
|
'5', // CONFIG (35 = magenta)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_CYAN), // DEBUG
|
'6', // DEBUG (36 = cyan)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GRAY), // VERBOSE
|
'7', // VERBOSE (37 = gray)
|
||||||
ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_WHITE), // VERY_VERBOSE
|
'8', // VERY_VERBOSE (38 = white)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const LOG_LEVEL_LETTERS[] = {
|
static constexpr char LOG_LEVEL_LETTER_CHARS[] = {
|
||||||
"", // NONE
|
'\0', // NONE
|
||||||
"E", // ERROR
|
'E', // ERROR
|
||||||
"W", // WARNING
|
'W', // WARNING
|
||||||
"I", // INFO
|
'I', // INFO
|
||||||
"C", // CONFIG
|
'C', // CONFIG
|
||||||
"D", // DEBUG
|
'D', // DEBUG
|
||||||
"V", // VERBOSE
|
'V', // VERBOSE (VERY_VERBOSE uses two 'V's)
|
||||||
"VV", // VERY_VERBOSE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Maximum header size: 35 bytes fixed + 32 bytes tag + 16 bytes thread name = 83 bytes (45 byte safety margin)
|
||||||
|
static constexpr uint16_t MAX_HEADER_SIZE = 128;
|
||||||
|
|
||||||
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
||||||
/** Enum for logging UART selection
|
/** Enum for logging UART selection
|
||||||
*
|
*
|
||||||
@@ -215,14 +217,6 @@ class Logger : public Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format string to explicit buffer with varargs
|
|
||||||
inline void printf_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format, ...) {
|
|
||||||
va_list arg;
|
|
||||||
va_start(arg, format);
|
|
||||||
this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg);
|
|
||||||
va_end(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef USE_HOST
|
#ifndef USE_HOST
|
||||||
const LogString *get_uart_selection_();
|
const LogString *get_uart_selection_();
|
||||||
#endif
|
#endif
|
||||||
@@ -318,26 +312,67 @@ class Logger : public Component {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline void copy_string(char *buffer, uint16_t &pos, const char *str) {
|
||||||
|
const size_t len = strlen(str);
|
||||||
|
// Intentionally no null terminator, building larger string
|
||||||
|
memcpy(buffer + pos, str, len); // NOLINT(bugprone-not-null-terminated-result)
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_ansi_color_for_level(char *buffer, uint16_t &pos, uint8_t level) {
|
||||||
|
if (level == 0)
|
||||||
|
return;
|
||||||
|
// Construct ANSI escape sequence: "\033[{bold};3{color}m"
|
||||||
|
// Example: "\033[1;31m" for ERROR (bold red)
|
||||||
|
buffer[pos++] = '\033';
|
||||||
|
buffer[pos++] = '[';
|
||||||
|
buffer[pos++] = (level == 1) ? '1' : '0'; // Only ERROR is bold
|
||||||
|
buffer[pos++] = ';';
|
||||||
|
buffer[pos++] = '3';
|
||||||
|
buffer[pos++] = LOG_LEVEL_COLOR_DIGIT[level];
|
||||||
|
buffer[pos++] = 'm';
|
||||||
|
}
|
||||||
|
|
||||||
inline void HOT write_header_to_buffer_(uint8_t level, const char *tag, int line, const char *thread_name,
|
inline void HOT write_header_to_buffer_(uint8_t level, const char *tag, int line, const char *thread_name,
|
||||||
char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
||||||
// Format header
|
uint16_t pos = *buffer_at;
|
||||||
// uint8_t level is already bounded 0-255, just ensure it's <= 7
|
// Early return if insufficient space - intentionally don't update buffer_at to prevent partial writes
|
||||||
if (level > 7)
|
if (pos + MAX_HEADER_SIZE > buffer_size)
|
||||||
level = 7;
|
return;
|
||||||
|
|
||||||
const char *color = esphome::logger::LOG_LEVEL_COLORS[level];
|
// Construct: <color>[LEVEL][tag:line]:
|
||||||
const char *letter = esphome::logger::LOG_LEVEL_LETTERS[level];
|
write_ansi_color_for_level(buffer, pos, level);
|
||||||
|
buffer[pos++] = '[';
|
||||||
|
if (level != 0) {
|
||||||
|
if (level >= 7) {
|
||||||
|
buffer[pos++] = 'V'; // VERY_VERBOSE = "VV"
|
||||||
|
buffer[pos++] = 'V';
|
||||||
|
} else {
|
||||||
|
buffer[pos++] = LOG_LEVEL_LETTER_CHARS[level];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer[pos++] = ']';
|
||||||
|
buffer[pos++] = '[';
|
||||||
|
copy_string(buffer, pos, tag);
|
||||||
|
buffer[pos++] = ':';
|
||||||
|
buffer[pos++] = '0' + (line / 100) % 10;
|
||||||
|
buffer[pos++] = '0' + (line / 10) % 10;
|
||||||
|
buffer[pos++] = '0' + line % 10;
|
||||||
|
buffer[pos++] = ']';
|
||||||
|
|
||||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
||||||
if (thread_name != nullptr) {
|
if (thread_name != nullptr) {
|
||||||
// Non-main task with thread name
|
write_ansi_color_for_level(buffer, pos, 1); // Always use bold red for thread name
|
||||||
this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line,
|
buffer[pos++] = '[';
|
||||||
ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), thread_name, color);
|
copy_string(buffer, pos, thread_name);
|
||||||
return;
|
buffer[pos++] = ']';
|
||||||
|
write_ansi_color_for_level(buffer, pos, level); // Restore original color
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Main task or non ESP32/LibreTiny platform
|
|
||||||
this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]: ", color, letter, tag, line);
|
buffer[pos++] = ':';
|
||||||
|
buffer[pos++] = ' ';
|
||||||
|
*buffer_at = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void HOT format_body_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format,
|
inline void HOT format_body_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format,
|
||||||
|
@@ -168,8 +168,9 @@ class ComponentIterator {
|
|||||||
UPDATE,
|
UPDATE,
|
||||||
#endif
|
#endif
|
||||||
MAX,
|
MAX,
|
||||||
} state_{IteratorState::NONE};
|
};
|
||||||
uint16_t at_{0}; // Supports up to 65,535 entities per type
|
uint16_t at_{0}; // Supports up to 65,535 entities per type
|
||||||
|
IteratorState state_{IteratorState::NONE};
|
||||||
bool include_internal_{false};
|
bool include_internal_{false};
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
|
@@ -192,7 +192,7 @@ def install_custom_components_meta_finder():
|
|||||||
install_meta_finder(custom_components_dir)
|
install_meta_finder(custom_components_dir)
|
||||||
|
|
||||||
|
|
||||||
def _lookup_module(domain, exception):
|
def _lookup_module(domain: str, exception: bool) -> ComponentManifest | None:
|
||||||
if domain in _COMPONENT_CACHE:
|
if domain in _COMPONENT_CACHE:
|
||||||
return _COMPONENT_CACHE[domain]
|
return _COMPONENT_CACHE[domain]
|
||||||
|
|
||||||
@@ -219,16 +219,16 @@ def _lookup_module(domain, exception):
|
|||||||
return manif
|
return manif
|
||||||
|
|
||||||
|
|
||||||
def get_component(domain, exception=False):
|
def get_component(domain: str, exception: bool = False) -> ComponentManifest | None:
|
||||||
assert "." not in domain
|
assert "." not in domain
|
||||||
return _lookup_module(domain, exception)
|
return _lookup_module(domain, exception)
|
||||||
|
|
||||||
|
|
||||||
def get_platform(domain, platform):
|
def get_platform(domain: str, platform: str) -> ComponentManifest | None:
|
||||||
full = f"{platform}.{domain}"
|
full = f"{platform}.{domain}"
|
||||||
return _lookup_module(full, False)
|
return _lookup_module(full, False)
|
||||||
|
|
||||||
|
|
||||||
_COMPONENT_CACHE = {}
|
_COMPONENT_CACHE: dict[str, ComponentManifest] = {}
|
||||||
CORE_COMPONENTS_PATH = (Path(__file__).parent / "components").resolve()
|
CORE_COMPONENTS_PATH = (Path(__file__).parent / "components").resolve()
|
||||||
_COMPONENT_CACHE["esphome"] = ComponentManifest(esphome.core.config)
|
_COMPONENT_CACHE["esphome"] = ComponentManifest(esphome.core.config)
|
||||||
|
Reference in New Issue
Block a user