Build version string incrementally from PROGMEM literals using
ESPHOME_strncpy_P and ESPHOME_strncat_P. Write hash and build time
directly into buffer without temporary variables. Calculate buffer
size based on actual components needed.
Add ESPHOME_strncat_P macro to progmem.h for cross-platform PROGMEM
string concatenation.
Build version string incrementally from PROGMEM literal prefix, avoiding
format strings in RAM. Copy from PROGMEM on ESP8266, use directly on
other platforms.
Store format string in PROGMEM and copy to RAM buffer on ESP8266 before
use. On other platforms, use the format string directly. This saves RAM
on ESP8266 while maintaining the same functionality.
Replace str_sprintf() with snprintf_P() and PSTR() to keep format
strings in flash instead of RAM. Also removes 'config hash 0x' prefix
to save additional bytes.
Add Application::get_config_version_hash() as a constexpr that returns
fnv1a_hash_extend(config_hash, ESPHOME_VERSION).
Make get_config_hash(), get_build_time(), fnv1a_hash(), and
fnv1a_hash_extend() constexpr inline functions.
Replace open-coded fnv1a_hash_extend(config_hash, ESPHOME_VERSION)
calls with get_config_version_hash() in sensor and wifi components.
Remove now-unnecessary version.h includes from component files.
Add tests covering the logic that detects when source files are removed:
- test_copy_src_tree_detects_removed_source_file: Verifies that removing
a regular source file triggers sources_changed flag
- test_copy_src_tree_ignores_removed_generated_file: Verifies that removing
a generated file (like build_info_data.h) does not trigger sources_changed
Change MQTT sw_version and version text sensor to display config_hash
instead of build_time_str. Format: "(config hash 0xXXXXXXXX)"
Version sensor with hide_timestamp=false also includes build time:
"(config hash 0xXXXXXXXX, built: YYYY-MM-DD HH:MM:SS +ZZZZ)"
Change wifi component to use fnv1a_hash_extend(config_hash, ESPHOME_VERSION)
instead of fnv1_hash(compilation_time) for the preferences hash.
This ensures wifi settings are invalidated on config or version changes,
not just on recompilation.
Change sen5x, sgp30, and sgp4x components to use fnv1a_hash_extend()
starting with config_hash and ESPHOME_VERSION, then extending with the
sensor serial number. This replaces the previous use of fnv1_hash with
compilation_time.
This ensures baseline storage is invalidated on config or version
changes, not just on recompilation.
Keep the API DeviceInfo compilation_time field using the old
get_compilation_time_ref() format for backward compatibility.
The text sensor build_time_str continues to use the new ISO 8601 format.
Increase buffer from 24 to 26 bytes to accommodate the ISO 8601 format
with timezone: "YYYY-MM-DD HH:MM:SS +ZZZZ" (25 chars + null terminator).
The old format "Dec 15 2025, 18:14:59" was 20 chars, but the new format
needs 25 chars. The 24-byte buffer was truncating the timezone to "+00"
instead of "+0000".
Change the API's DeviceInfo response to use the new ISO 8601 format
with timezone for compilation_time field by calling get_build_time_string()
instead of get_compilation_time_ref().
Update the placeholder build_info_data.h to match the new format.
Update integration test to expect the new format for compilation_time.
Test verifies that:
- When source files change, build_info is regenerated with new timestamp
- When no files change, build_info is preserved with same timestamp
The test runs copy_src_tree() three times in the same environment:
1. Initial run creates build_info
2. Second run with no changes preserves the timestamp
3. Third run with changed source file regenerates with new timestamp
Add tests to cover:
- Detection of config_hash changes in existing build_info.json
- Detection of esphome_version changes in existing build_info.json
- Handling of invalid/corrupted build_info.json files
These tests cover the exception handling and change detection logic
in copy_src_tree() that checks the existing build_info.json.
Use YYYY-MM-DD HH:MM:SS +ZZZZ format instead of the locale-dependent
'%b %d %Y, %H:%M:%S' format. This provides:
- Unambiguous date format (YYYY-MM-DD)
- Timezone information
- Locale-independent formatting
- Better sortability and parseability
Example: "2025-12-15 16:30:27 +0000" instead of "Dec 15 2025, 16:30:27"
Tests validate the format using strptime with '%Y-%m-%d %H:%M:%S %z'.