Avoid per-file HTTP HEAD requests during config validation when running
esphome logs against a previously-cached project. The skip_external_update
flag was already plumbed for git operations, but external_files.download_content
ignored it. Thread it through CORE so audio_file, micro_wake_word,
speaker/media_player, image, font, and bme68x_bsec2 reuse cached files
without per-URL network round-trips when the file already exists locally.
- Add `--` terminator before submodule paths (both clone and refresh
paths) so a path beginning with `-` cannot be parsed as a git option.
- Reword the refresh-fetch comment: this fetch also runs when ref is
None, in which case it pulls the remote default branch.
Fixesesphome/esphome#11550
When clone_or_update is called with a ref or submodules, the initial
clone uses --depth=1 but the subsequent git fetch and git submodule
update commands run deep, pulling the full history on every refresh.
This causes excess network traffic and disk usage for external_components,
packages, and dashboard imports.
Add --depth=1 to all four call sites (initial fetch, initial submodule
init, refresh fetch, refresh submodule update). Shallow fetches still
advance the local clone to the current remote tip when it moves, so the
refresh path keeps working as before.
Wrap the on_finished_playback CallbackManager storage, registration
method and call site behind USE_RTTTL_FINISHED_PLAYBACK_CALLBACK so
configs without an on_finished_playback automation pay zero RAM and
zero flash for it.
Keeps CallbackManager rather than switching to StaticCallbackManager
because rtttl is MULTI_CONF — a per-class compile-time N would force
every instance to reserve max(callbacks_per_instance) slots.
EsphomeLogsHandler.build_command now appends --no-states to the
spawned `esphome logs` argv when the WebSocket spawn message
includes `no_states: true`. This lets the dashboard frontend
suppress entity-state log lines for OTA log sessions without
requiring users to drop to the CLI.
Adds three unit tests covering the truthy, missing, and explicit-False
cases.
- script/build_helpers.py: when injecting a non-MULTI_CONF component
into the post-validation config, run its CONFIG_SCHEMA with {} so
defaults are populated. Without this, socket got config = {} and
socket.FILTER_SOURCE_FILES crashed with KeyError on
'implementation' (the schema's defaulted key was never filled in).
Falls back to {} if the schema can't validate empty input.
- tests/components/json/__init__.py: enable codegen for json so its
to_code runs during cpp unit test builds, registering the
ArduinoJson library. Required for any api dep test, since
json_util.cpp #includes <ArduinoJson.h>.
Locally verified 'script/cpp_unit_test.py api' now compiles and runs;
ProtoMacVarint test suite (9 cases) passes.
- Test file: declare proto_debug_end_ locally instead of misusing
PROTO_ENCODE_DEBUG_INIT (which expands to a comma+expression for
appending to a function call, not a standalone statement). Add
NOLINTNEXTLINE on the deterministic mt19937_64 seed so clang-tidy
cert-msc32-c stops failing the build (the seed is intentional for
reproducible test runs).
- socket FILTER_SOURCE_FILES: tolerate non-dict CORE.config['socket']
(e.g. C++ unit-test builds where socket isn't validated as a
mapping). Returning [] is safe -- all impl files are guarded by
USE_SOCKET_IMPL_* defines so only the selected one contributes
code.
Verifies encode_varint_raw_48bit and calc_uint64_48bit_force for the
8 corner-case MAC addresses requested in review:
00:00:00:00:00:00, 11:00:00:00:00:00, 00:AA:00:00:00:00,
00:00:BB:00:00:00, 00:00:00:CC:00:00, 00:00:00:00:DD:00,
00:00:00:00:00:EE, FF:FF:FF:FF:FF:FF
For each value the test asserts byte-identical output to the reference
encode_varint_raw_64 loop, the expected encoded byte length, agreement
with calc_uint64_48bit_force, and round-trip through a generic varint
decoder. Adds a 100-value deterministic-random sample across the full
48-bit space for additional coverage.
Cover the four paths introduced by the wake split:
- default manifests (recursive_sources=False) skip subdirs entirely,
- opt-in manifests walk non-subpackage subdirs with /-joined paths,
- subdirs containing __init__.py are skipped to avoid double-counting
existing component subpackages, and __pycache__ is always skipped,
- FILTER_SOURCE_FILES entries accept /-joined subpaths.
Every \`esphome\` CLI invocation pays the cost of whatever \`esphome/__main__.py\`
imports at module scope before the requested command even runs. This
moves three heavy imports into the functions that actually use them:
- \`esphome.zeroconf\` (discover_mdns_devices): only needed for the
name_add_mac_suffix OTA discovery path.
- \`esphome.writer\`: only needed by compile/clean paths.
- \`esphome.yaml_util\`: only needed by codegen, config dump, and rename.
Local measurement drops from ~75ms to ~47ms (-37%) for a cold
\`python -c 'import esphome.__main__'\`. The zeroconf chain alone accounts
for most of the gain — the case that motivated the CI budget check.
Also adds a module-level note explaining the intent so future PRs don't
innocently promote these back to the top.
Retargets four test patches from \`esphome.__main__.discover_mdns_devices\`
to \`esphome.zeroconf.discover_mdns_devices\` now that the symbol is only
bound inside the function that calls it.
- determine-jobs: trigger on changes to requirements_test.txt too; that
file is hashed into the venv cache key and installed during
restore-python, so a change there can alter the import environment.
- ci.yml: merge the --check and --har steps so we only run
importtime-waterfall once per job (was measuring twice: ~7-8s of
wasted CI time per run). Uses the new script/check_import_time.py
--check --har <path> combination; the HAR reflects the same
measurement that produced the pass/fail decision.
- script/check_import_time.py: refactor the CLI so --har is a standalone
option rather than a mutually-exclusive mode. --check and --update
each accept an optional --har PATH that writes the HAR from the same
subprocess invocation. Plain --har is still supported for local use.
- tests: add tests/script/test_check_import_time.py covering HAR parsing,
root lookup, offender ranking/dedup, budget round-trip, and the three
--check exit paths (pass, regression, missing budget) plus the new
--check --har combined write. Add requirements_test.txt case to the
should_run_import_time parametrized test.
The previous parser walked `-X importtime` stderr by hand (string-splitting
on `|`, indent-width math). Replace it with a load of the HAR JSON that
importtime-waterfall already produces: each entry carries the module name,
self-time, and cumulative — no tree reconstruction needed. Drops the
hand-rolled retry loop too, since importtime-waterfall does best-of-6
internally.
The committed budget (75.2ms) was seeded on a fast local machine; GHA
runners measured 122.8ms, so the first CI run tripped the check. Reset
the baseline to 123ms with a 25% margin (ceiling ~154ms) to absorb GHA
variance. Tighten later once we have several data points.
Adds unit tests for should_run_import_time across the trigger matrix and
wires the new mock into the existing test_main_* suite.