1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 16:51:52 +00:00

Create and use buildinfo.json instead of parsing linker script

Co-authored-by: J. Nick Koston <nick+github@koston.org>
This commit is contained in:
David Woodhouse
2025-12-13 11:57:04 +09:00
parent d8c52297ab
commit 12e0d6bdcc
2 changed files with 39 additions and 27 deletions

View File

@@ -528,44 +528,37 @@ def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
def _check_and_emit_buildinfo():
"""Check if firmware was rebuilt and emit buildinfo."""
import json
firmware_path = CORE.firmware_bin
buildinfo_ld_path = CORE.relative_build_path("buildinfo.ld")
buildinfo_json_path = CORE.relative_build_path("buildinfo.json")
# Check if both files exist
if not firmware_path.exists() or not buildinfo_ld_path.exists():
if not firmware_path.exists() or not buildinfo_json_path.exists():
return
# Check if firmware is newer than buildinfo linker script (indicating a relink occurred)
if firmware_path.stat().st_mtime <= buildinfo_ld_path.stat().st_mtime:
# Check if firmware is newer than buildinfo (indicating a relink occurred)
if firmware_path.stat().st_mtime <= buildinfo_json_path.stat().st_mtime:
return
# Read buildinfo values from linker script
# Read buildinfo from JSON
try:
with open(buildinfo_ld_path, encoding="utf-8") as f:
content = f.read()
except OSError as e:
with open(buildinfo_json_path, encoding="utf-8") as f:
buildinfo = json.load(f)
except (OSError, json.JSONDecodeError) as e:
_LOGGER.debug("Failed to read buildinfo: %s", e)
return
config_hash_match = re.search(r"ESPHOME_CONFIG_HASH = 0x([0-9a-fA-F]+);", content)
build_time_match = re.search(r"ESPHOME_BUILD_TIME = (\d+);", content)
config_hash = buildinfo.get("config_hash")
build_time = buildinfo.get("build_time")
if not config_hash_match or not build_time_match:
if config_hash is None or build_time is None:
return
config_hash = config_hash_match.group(1)
build_time = int(build_time_match.group(1))
# Emit buildinfo
print("=== ESPHome Build Info ===")
print(f"Config Hash: 0x{config_hash}")
print(
f"Build Time: {build_time} ({time.strftime('%Y-%m-%d %H:%M:%S %z', time.localtime(build_time))})"
_LOGGER.info(
"Build Info: config_hash=0x%08x build_time=%s", config_hash, build_time
)
print("===========================")
# TODO: Future commit will create JSON manifest with OTA metadata here
def upload_using_esptool(

View File

@@ -1,5 +1,6 @@
from collections.abc import Callable
import importlib
import json
import logging
import os
from pathlib import Path
@@ -249,8 +250,16 @@ def copy_src_tree():
write_file_if_changed(
CORE.relative_src_path("esphome", "core", "version.h"), generate_version_h()
)
# Write buildinfo linker script and copy the PlatformIO script
write_file(CORE.relative_build_path("buildinfo.ld"), generate_buildinfo_ld())
# Write buildinfo linker script, JSON metadata, and copy the PlatformIO script
config_hash, build_time, build_time_str = get_buildinfo()
write_file(
CORE.relative_build_path("buildinfo.ld"),
generate_buildinfo_ld(config_hash, build_time, build_time_str),
)
write_file(
CORE.relative_build_path("buildinfo.json"),
json.dumps({"config_hash": config_hash, "build_time": build_time}),
)
copy_file_if_changed(
Path(__file__).parent / "core" / "buildinfo.py.script",
CORE.relative_build_path("buildinfo.py"),
@@ -306,17 +315,27 @@ def _encode_string_symbols(
return symbols
def generate_buildinfo_ld() -> str:
"""Generate buildinfo linker script with config hash and build time."""
def get_buildinfo() -> tuple[int, int, str]:
"""Calculate buildinfo values from current config.
Returns:
Tuple of (config_hash, build_time, build_time_str)
"""
from esphome import yaml_util
# Use the same clean YAML representation as 'esphome config' command
config_str = yaml_util.dump(CORE.config, show_secrets=True)
config_hash = fnv1a_32bit_hash(config_str)
config_hash_str = f"{config_hash:08x}"
build_time = int(time.time())
build_time_str = time.strftime("%b %d %Y, %H:%M:%S", time.localtime(build_time))
return config_hash, build_time, build_time_str
def generate_buildinfo_ld(
config_hash: int, build_time: int, build_time_str: str
) -> str:
"""Generate buildinfo linker script with config hash and build time."""
config_hash_str = f"{config_hash:08x}"
# Generate symbols for all 4 variants: 32LE, 32BE, 64LE, 64BE
all_variants: list[str] = []