From f28ac8687973dfc6e34dc61fd966e3befa9c8ab7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 8 Mar 2026 01:17:03 -1000 Subject: [PATCH 1/4] Add enable_full_printf escape hatch --- esphome/components/esp8266/__init__.py | 11 +++++++---- esphome/components/esp8266/const.py | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index a3219f1910f..4892293738d 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -23,6 +23,7 @@ from esphome.helpers import copy_file_if_changed from .boards import BOARDS, ESP8266_LD_SCRIPTS from .const import ( CONF_EARLY_PIN_INIT, + CONF_ENABLE_FULL_PRINTF, CONF_ENABLE_SERIAL, CONF_ENABLE_SERIAL1, CONF_RESTORE_FROM_FLASH, @@ -179,6 +180,7 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_ENABLE_SERIAL): cv.boolean, cv.Optional(CONF_ENABLE_SERIAL1): cv.boolean, + cv.Optional(CONF_ENABLE_FULL_PRINTF, default=False): cv.boolean, } ), set_core_data, @@ -260,10 +262,11 @@ async def to_code(config): if CORE.testing_mode: cg.add_build_flag("-DESPHOME_TESTING_MODE") - # Wrap FILE*-based printf functions to eliminate newlib's _vfprintf_r - # (~900 bytes). See printf_stubs.cpp for implementation. - for symbol in ("vprintf", "printf", "fprintf"): - cg.add_build_flag(f"-Wl,--wrap={symbol}") + # Wrap FILE*-based printf functions to eliminate newlib's _vfiprintf_r + # (~1.6 KB). See printf_stubs.cpp for implementation. + if not config.get(CONF_ENABLE_FULL_PRINTF): + for symbol in ("vprintf", "printf", "fprintf"): + cg.add_build_flag(f"-Wl,--wrap={symbol}") cg.add_platformio_option("board_build.flash_mode", config[CONF_BOARD_FLASH_MODE]) diff --git a/esphome/components/esp8266/const.py b/esphome/components/esp8266/const.py index 229ac61f245..57eb54f0f80 100644 --- a/esphome/components/esp8266/const.py +++ b/esphome/components/esp8266/const.py @@ -6,6 +6,7 @@ KEY_BOARD = "board" KEY_PIN_INITIAL_STATES = "pin_initial_states" CONF_RESTORE_FROM_FLASH = "restore_from_flash" CONF_EARLY_PIN_INIT = "early_pin_init" +CONF_ENABLE_FULL_PRINTF = "enable_full_printf" CONF_ENABLE_SERIAL = "enable_serial" CONF_ENABLE_SERIAL1 = "enable_serial1" KEY_FLASH_SIZE = "flash_size" From 66374edd6deb93e51266e952b33ce5906ba4a624 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 8 Mar 2026 01:20:47 -1000 Subject: [PATCH 2/4] Fix comments: ESP8266 logging uses Serial, not ets_printf --- esphome/components/esp8266/__init__.py | 4 +++- esphome/components/esp8266/printf_stubs.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index 4892293738d..1ef4f5e037e 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -264,7 +264,9 @@ async def to_code(config): # Wrap FILE*-based printf functions to eliminate newlib's _vfiprintf_r # (~1.6 KB). See printf_stubs.cpp for implementation. - if not config.get(CONF_ENABLE_FULL_PRINTF): + if config.get(CONF_ENABLE_FULL_PRINTF): + cg.add_define("USE_FULL_PRINTF") + else: for symbol in ("vprintf", "printf", "fprintf"): cg.add_build_flag(f"-Wl,--wrap={symbol}") diff --git a/esphome/components/esp8266/printf_stubs.cpp b/esphome/components/esp8266/printf_stubs.cpp index 374c0015237..4eb316d6ec7 100644 --- a/esphome/components/esp8266/printf_stubs.cpp +++ b/esphome/components/esp8266/printf_stubs.cpp @@ -3,14 +3,14 @@ * * The ESP8266 Arduino framework and libraries may reference printf(), * vprintf(), and fprintf() which pull in newlib's _vfprintf_r (~900 bytes). - * ESPHome never uses these — all logging goes through ets_printf/ets_vsnprintf - * directly, so the libc FILE*-based printf path is dead code. + * ESPHome never uses these — all logging writes directly to the UART via + * Arduino's Serial, so the libc FILE*-based printf path is dead code. * * These stubs redirect through vsnprintf() (which is already in the binary * for ESPHome's logging) and fwrite(), allowing the linker to dead-code * eliminate _vfprintf_r. * - * Saves ~900 bytes of flash. + * Saves ~1.6 KB of flash. */ #if defined(USE_ESP8266) && !defined(USE_FULL_PRINTF) @@ -22,8 +22,8 @@ namespace esphome::esp8266 {} static constexpr size_t PRINTF_BUFFER_SIZE = 256; -// These stubs are essentially dead code at runtime — ESPHome uses ets_printf -// for logging, and the Arduino core's Serial.printf() has its own implementation. +// These stubs are essentially dead code at runtime — ESPHome writes directly +// to the UART via Arduino's Serial, and Serial.printf() has its own implementation. // The buffer overflow check is purely defensive and should never trigger. static int write_printf_buffer(FILE *stream, char *buf, int len) { if (len < 0) { From 3d1f7cea72e008edf0e827520fcfb3189db09b67 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 8 Mar 2026 01:26:31 -1000 Subject: [PATCH 3/4] Increase printf stub buffer to 512 bytes to match ESP32 --- esphome/components/esp8266/printf_stubs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp8266/printf_stubs.cpp b/esphome/components/esp8266/printf_stubs.cpp index 4eb316d6ec7..e6d4a748664 100644 --- a/esphome/components/esp8266/printf_stubs.cpp +++ b/esphome/components/esp8266/printf_stubs.cpp @@ -20,7 +20,7 @@ namespace esphome::esp8266 {} -static constexpr size_t PRINTF_BUFFER_SIZE = 256; +static constexpr size_t PRINTF_BUFFER_SIZE = 512; // These stubs are essentially dead code at runtime — ESPHome writes directly // to the UART via Arduino's Serial, and Serial.printf() has its own implementation. From 1e3eac2568e3ca31a98d55a152ff8bd351d90cd7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 8 Mar 2026 01:30:31 -1000 Subject: [PATCH 4/4] Add enable_full_printf test coverage --- tests/components/esp8266/test.esp8266-ard.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/components/esp8266/test.esp8266-ard.yaml b/tests/components/esp8266/test.esp8266-ard.yaml index 039a2610160..c77218f7a3c 100644 --- a/tests/components/esp8266/test.esp8266-ard.yaml +++ b/tests/components/esp8266/test.esp8266-ard.yaml @@ -1,3 +1,6 @@ +esp8266: + enable_full_printf: false + logger: level: VERBOSE