Compare commits

..
2535 Commits
Author SHA1 Message Date
J. Nick Koston af43c31d45 Merge branch 'pch-strict-ci' into host-pch 2026-09-28 11:50:49 +02:00
J. Nick Koston 0c87abb3b4 Merge branch 'platformio-pch-libretiny' into pch-strict-ci
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-09-28 11:50:35 +02:00
J. Nick Koston 6b619ed973 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-28 11:50:11 +02:00
J. Nick Koston e9f7e00f78 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-28 11:50:10 +02:00
J. Nick Koston bc323e74aa Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-28 11:50:10 +02:00
J. Nick Koston 26b8186a73 Emit the precompiled header through a named function in the shared generator 2026-09-28 11:49:41 +02:00
J. Nick Koston b2c3b954d6 Precompile the host prefix on the ninja build through one shared helper 2026-09-28 11:45:48 +02:00
J. Nick Koston f28b569e9f Merge branch 'pch-strict-ci' into host-pch
# Conflicts:
#	esphome/components/host/__init__.py
2026-09-28 11:38:30 +02:00
J. Nick Koston 66717016d7 Merge branch 'platformio-pch-libretiny' into pch-strict-ci
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-09-28 11:36:36 +02:00
J. Nick Koston 440c78c4ea Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-28 11:36:04 +02:00
J. Nick Koston e93ebf120f Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-28 11:36:03 +02:00
J. Nick Koston 8695e9a7c7 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-28 11:36:03 +02:00
J. Nick Koston 38b06cbfbd Merge remote-tracking branch 'origin/dev' into esp8266-native-pch
# Conflicts:
#	esphome/arduino8266/framework.py
#	esphome/build_gen/arduino8266.py
#	esphome/build_helpers/ccache.py
#	tests/unit_tests/build_helpers/test_ccache.py
#	tests/unit_tests/test_arduino8266_toolchain.py
2026-09-28 11:35:49 +02:00
J. Nick Koston deca3d89be Merge branch 'pch-strict-ci' into host-pch 2026-09-26 21:01:36 +01:00
J. Nick Koston 52c71d4ecc Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 21:01:36 +01:00
J. Nick Koston d4c053bffb Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 21:01:36 +01:00
J. Nick Koston 0dc12d57a9 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 21:01:35 +01:00
J. Nick Koston d96b85b8de Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 21:01:35 +01:00
J. Nick Koston 9570f19c09 Merge remote-tracking branch 'origin/dev' into esp8266-native-pch 2026-09-26 21:01:19 +01:00
J. Nick Koston 715cb55d46 Merge branch 'pch-strict-ci' into host-pch 2026-09-26 20:50:35 +01:00
J. Nick Koston 7010858b19 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 20:50:34 +01:00
J. Nick Koston e7a7768e96 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 20:50:34 +01:00
J. Nick Koston d052d8a01d Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 20:50:34 +01:00
J. Nick Koston f613101703 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 20:50:26 +01:00
J. Nick Koston 36b60e585a Merge branch 'esp8266-native-ci' into esp8266-native-pch
# Conflicts:
#	esphome/build_helpers/idedata.py
#	esphome/components/esp8266/__init__.py
#	script/determine-jobs.py
#	tests/script/test_determine_jobs.py
#	tests/unit_tests/test_arduino8266_toolchain.py
2026-09-26 20:49:30 +01:00
J. Nick Koston 06a26ee57c Trigger the smoke tests when the shared build configs change 2026-09-26 20:47:51 +01:00
J. Nick Koston c125310f66 Check the blank component list before discovery
The guard validates arguments, so it reads better next to the other
early exit than after the loop that already skips blank patterns.
2026-09-26 20:44:15 +01:00
J. Nick Koston b695dde1c3 Add the native ESP8266 CI smoke test
Runs the test_build_components matrix with --toolchain arduino behind
a cached framework install, and teaches determine-jobs which changes
must trigger it.
2026-09-26 20:44:15 +01:00
J. Nick Koston d5b237f6e2 Merge branch 'pch-strict-ci' into host-pch 2026-09-26 11:25:05 +01:00
J. Nick Koston 7465c1ef02 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 11:25:05 +01:00
J. Nick Koston 1bcab7f2b8 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 11:25:05 +01:00
J. Nick Koston 0bf4f5dfba Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 11:25:05 +01:00
J. Nick Koston 45e79648a0 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 11:25:04 +01:00
J. Nick Koston 3390a13e8c Merge branch 'esp8266-native-ci' into esp8266-native-pch
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-09-26 11:24:50 +01:00
J. Nick Koston 5cb3ec2ac4 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-ci 2026-09-26 11:24:31 +01:00
J. Nick Koston 3bbe673ee5 Resolve the native backend from one shared table
The (platform, toolchain) mapping lived in both __main__ and the esp8266
component, so a renamed backend module meant editing two places and the
drift test only covered one. build_helpers/native.py now holds it; the
module stays import-light so the serial upload and logs fast path can
resolve a backend without pulling in a platform package.
2026-09-26 11:24:13 +01:00
J. Nick Koston d7075fbd5b Merge branch 'pch-strict-ci' into host-pch 2026-09-26 10:35:52 +01:00
J. Nick Koston 875615561c Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 10:35:52 +01:00
J. Nick Koston d4e741d419 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 10:35:51 +01:00
J. Nick Koston 26d6baea6c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 10:35:51 +01:00
J. Nick Koston 32e699c4e4 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 10:35:51 +01:00
J. Nick Koston 831897c93b Merge branch 'esp8266-native-ci' into esp8266-native-pch 2026-09-26 10:35:51 +01:00
J. Nick Koston 6eab575dc5 Check the blank component list before discovery
The guard validates arguments, so it reads better next to the other
early exit than after the loop that already skips blank patterns.
2026-09-26 10:35:50 +01:00
J. Nick Koston 2d162da693 Merge branch 'pch-strict-ci' into host-pch 2026-09-26 10:32:27 +01:00
J. Nick Koston 2b9c549a0c Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 10:32:27 +01:00
J. Nick Koston 8b41b14528 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 10:32:27 +01:00
J. Nick Koston 17bac02770 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 10:32:26 +01:00
J. Nick Koston 0d0a808e49 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 10:32:26 +01:00
J. Nick Koston 75cece4f4f Merge branch 'esp8266-native-ci' into esp8266-native-pch 2026-09-26 10:32:26 +01:00
J. Nick Koston cf6ada1e85 Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain 2026-09-26 10:32:25 +01:00
J. Nick Koston 47321da57c Merge branch 'esp8266-arduino-toolchain' into esp8266-native-ci 2026-09-26 10:32:25 +01:00
J. Nick Koston 22fa536fa5 Simplify the native toolchain driver
Drops the ninja dry-run probe (a second full manifest load and stat
sweep per build to suppress one line), the compile-database stamp file
(a plain mtime compare says the same), and the ccache sentinel
(resolve_ccache_path only spawns when it returns a value, so a plain
fallback never re-probes). The crash decoder resolves addr2line and
the ELF once per run instead of once per address, which removes the
module-level warn-dedup dict along with its test fixture. The size
summary uses the toolchain path it was handed rather than re-deriving
it, and its two failure branches merge.

The framework import moves into the functions that need it: the serial
upload and logs fast path resolves this module for artifact paths
alone and was paying 16 ms and 29 modules for the package-download
stack. test_lazy_imports now guards that module so it cannot come
back. analyze-memory's idedata candidate list learns the suffixed
native cache name, and warn_if_idedata_missing goes back to being a
one-for-one extraction.
2026-09-26 10:31:52 +01:00
J. Nick Koston 83fd1646b4 Merge branch 'pch-strict-ci' into host-pch 2026-09-26 10:01:01 +01:00
J. Nick Koston ba4bb6c778 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-26 10:01:01 +01:00
J. Nick Koston e65aeff1e2 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-26 10:01:01 +01:00
J. Nick Koston bd329cdceb Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-26 10:01:01 +01:00
J. Nick Koston 94f83b4ee2 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-26 10:01:01 +01:00
J. Nick Koston 5d477af185 Merge branch 'esp8266-native-ci' into esp8266-native-pch 2026-09-26 10:01:00 +01:00
J. Nick Koston d1e8b5afcc Add the native ESP8266 CI smoke test
Runs the test_build_components matrix with --toolchain arduino behind
a cached framework install, and teaches determine-jobs which changes
must trigger it.
2026-09-26 10:00:44 +01:00
J. Nick Koston d16714de24 Move the native ESP8266 CI wiring to a follow-up PR
The smoke-test job, its cache action, and the job-determination and
harness changes that drive it land separately so this PR stays the
build driver alone.
2026-09-26 10:00:11 +01:00
J. Nick Koston 427c2f4cb3 Merge branch 'pch-strict-ci' into host-pch
# Conflicts:
#	esphome/writer.py
2026-09-25 16:22:52 +01:00
J. Nick Koston dbecf359ac Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-25 16:22:03 +01:00
J. Nick Koston d01748bc40 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-25 16:22:03 +01:00
J. Nick Koston 08e3b6af06 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-25 16:22:02 +01:00
J. Nick Koston 269374397e Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-25 16:22:02 +01:00
J. Nick Koston 25f600d437 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-25 16:22:02 +01:00
J. Nick Koston 739cc7fb5a Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain 2026-09-25 16:22:01 +01:00
J. Nick Koston ebbeb5a472 Merge branch 'pch-strict-ci' into host-pch 2026-09-24 17:35:37 +01:00
J. Nick Koston f5ba555acf Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-24 17:35:36 +01:00
J. Nick Koston 44dea178ad Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-24 17:35:36 +01:00
J. Nick Koston b91d4055fc Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-24 17:35:36 +01:00
J. Nick Koston 9ddd2c5ee1 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-24 17:35:35 +01:00
J. Nick Koston ce43590835 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-24 17:35:35 +01:00
J. Nick Koston 4db8af29b4 Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain 2026-09-24 17:35:35 +01:00
J. Nick Koston edbfd9a437 Merge branch 'pch-strict-ci' into host-pch 2026-09-24 14:10:05 +01:00
J. Nick Koston 4b289765d2 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-24 14:10:05 +01:00
J. Nick Koston a2b3c3b97e Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-24 14:10:05 +01:00
J. Nick Koston 78663302f3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-24 14:10:04 +01:00
J. Nick Koston 9a6b19e591 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-24 14:10:04 +01:00
J. Nick Koston 7a7fc6647b Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-24 14:10:04 +01:00
J. Nick Koston 61a0aad593 Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain 2026-09-24 14:10:03 +01:00
J. Nick Koston 9b24d56b39 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:46:57 +01:00
J. Nick Koston 5421f1dd94 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:46:57 +01:00
J. Nick Koston 2e129ee1d2 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:46:57 +01:00
J. Nick Koston 3ab48fcf59 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:46:56 +01:00
J. Nick Koston 58f83bed2f Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:46:56 +01:00
J. Nick Koston 0a00cc7133 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:46:56 +01:00
J. Nick Koston 4ade8d0515 Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	esphome/components/esp8266/__init__.py
2026-09-23 23:46:53 +01:00
J. Nick Koston 9f947c7cd8 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:36:23 +01:00
J. Nick Koston e992a400d8 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:36:23 +01:00
J. Nick Koston 0459efecf5 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:36:22 +01:00
J. Nick Koston 5f1a6d9b7b Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:36:22 +01:00
J. Nick Koston 84fa24205c Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:36:21 +01:00
J. Nick Koston 7750cdb72e Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:36:21 +01:00
J. Nick Koston 87968a3ea3 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-23 23:36:21 +01:00
J. Nick Koston cec0d05f96 Merge remote-tracking branch 'origin/dev' into esp8266-native-ninja-emission 2026-09-23 23:36:20 +01:00
J. Nick Koston 735e6d0fc3 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:23:00 +01:00
J. Nick Koston 8b3634fb34 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:23:00 +01:00
J. Nick Koston 961a3e176f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:23:00 +01:00
J. Nick Koston 2f63536667 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:23:00 +01:00
J. Nick Koston 8f8704d638 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:22:59 +01:00
J. Nick Koston ef3f6d3951 Read the extracted flag sets in the pch emission
The write_project split moved cxxflags into _resolve_flag_sets's
return; the pch layer's two reads follow it.
2026-09-23 23:22:57 +01:00
J. Nick Koston 64b52357b0 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:19:51 +01:00
J. Nick Koston 592699a96a Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:19:50 +01:00
J. Nick Koston efc8804867 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:19:50 +01:00
J. Nick Koston 0ae6d6d193 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:19:50 +01:00
J. Nick Koston 80a41ce453 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:19:50 +01:00
J. Nick Koston 73425d06a3 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-23 23:19:49 +01:00
J. Nick Koston 90a7c1dde2 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:19:49 +01:00
J. Nick Koston cc38e93214 Extract install checks and flag resolution from write_project
_check_install and _resolve_flag_sets pull ~110 lines out of the one
function body; behavior and emitted output are unchanged (the existing
end-to-end tests pass as-is).
2026-09-23 23:19:46 +01:00
J. Nick Koston a91874dcd9 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:13:21 +01:00
J. Nick Koston a6c3e48466 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:13:21 +01:00
J. Nick Koston 90eb7bbc5c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:13:21 +01:00
J. Nick Koston 57569404d9 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:13:20 +01:00
J. Nick Koston 62f0f0909a Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:13:20 +01:00
J. Nick Koston 3d6e5fd244 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-23 23:13:20 +01:00
J. Nick Koston 345106c56f Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:13:20 +01:00
J. Nick Koston c54e671a26 Check install completeness before spawning the linker-script gcc
A half-extracted framework cache now names the missing path instead of
surfacing a gcc failure; pure reorder, the checks depend on nothing
the generation step produces.
2026-09-23 23:13:03 +01:00
J. Nick Koston 45f4173ab5 Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:06:08 +01:00
J. Nick Koston 4a21970b24 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:06:08 +01:00
J. Nick Koston 08c4abf1ea Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:06:07 +01:00
J. Nick Koston f75206c707 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:06:07 +01:00
J. Nick Koston 0150b11a7f Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:06:07 +01:00
J. Nick Koston 2d79d1745d Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:06:07 +01:00
J. Nick Koston ce869366b8 Trim docstrings to repo standard 2026-09-23 23:06:04 +01:00
J. Nick Koston 94c3dd707f Merge branch 'pch-strict-ci' into host-pch 2026-09-23 23:02:49 +01:00
J. Nick Koston 2a86ab8d12 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 23:02:49 +01:00
J. Nick Koston 3341efba7a Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-23 23:02:49 +01:00
J. Nick Koston 958b7820ec Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 23:02:48 +01:00
J. Nick Koston f3e7399ab1 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 23:02:48 +01:00
J. Nick Koston 12fa602548 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 23:02:48 +01:00
J. Nick Koston c2406d5592 Trim comments to repo standard 2026-09-23 23:02:43 +01:00
J. Nick Koston a7b8642c2a Merge branch 'pch-strict-ci' into host-pch 2026-09-23 22:54:46 +01:00
J. Nick Koston 0cd6197873 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-23 22:54:46 +01:00
J. Nick Koston f25ce06a21 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny
# Conflicts:
#	esphome/components/libretiny/__init__.py
2026-09-23 22:54:43 +01:00
J. Nick Koston dfd52cb9c6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-23 22:54:18 +01:00
J. Nick Koston 2ec4456942 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-23 22:54:18 +01:00
J. Nick Koston 0f49668b76 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-23 22:54:18 +01:00
J. Nick Koston 4913034584 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-23 22:54:17 +01:00
J. Nick Koston 1f94d0e904 Merge remote-tracking branch 'origin/dev' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-09-23 22:54:13 +01:00
J. Nick Koston c09eaf5b36 Merge branch 'pch-strict-ci' into host-pch 2026-09-17 08:46:11 -05:00
J. Nick Koston 52a3f1f609 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-17 08:46:10 -05:00
J. Nick Koston 8fabbec5b5 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-17 08:46:10 -05:00
J. Nick Koston 6d74cf00da Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-17 08:46:10 -05:00
J. Nick Koston 5323693d8f Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-17 08:46:10 -05:00
J. Nick Koston 39ae4d4f41 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-17 08:46:09 -05:00
J. Nick Koston ff7b402241 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-17 08:46:09 -05:00
J. Nick Koston 6db112b694 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-17 08:46:09 -05:00
J. Nick Koston 43b3167cff Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-17 08:46:08 -05:00
J. Nick Koston c47c962cf2 Merge branch 'pch-strict-ci' into host-pch 2026-09-16 09:29:17 -05:00
J. Nick Koston 862c588b24 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-16 09:29:17 -05:00
J. Nick Koston 6254687dc3 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-16 09:29:17 -05:00
J. Nick Koston ac707c4304 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-16 09:29:16 -05:00
J. Nick Koston 7878616117 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-16 09:29:16 -05:00
J. Nick Koston 7eb91404fb Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-16 09:29:15 -05:00
J. Nick Koston 651a309034 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-16 09:29:15 -05:00
J. Nick Koston 3fecee6f9c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-16 09:29:15 -05:00
J. Nick Koston 5884b4c01b Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-16 09:29:06 -05:00
J. Nick Koston 8b8866307b Merge branch 'pch-strict-ci' into host-pch 2026-09-12 08:41:59 -05:00
J. Nick Koston d93556b0e0 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-12 08:41:58 -05:00
J. Nick Koston 11e553b353 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-12 08:41:58 -05:00
J. Nick Koston f7fe90e5da Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-12 08:41:58 -05:00
J. Nick Koston fdd62b0bc5 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-12 08:41:57 -05:00
J. Nick Koston 2938bd2e1c Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-12 08:41:57 -05:00
J. Nick Koston 75ff8ec543 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-12 08:41:57 -05:00
J. Nick Koston 4863aae192 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-12 08:41:56 -05:00
J. Nick Koston eed19f5eca Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-12 08:41:47 -05:00
J. Nick Koston c270336f03 Merge branch 'pch-strict-ci' into host-pch 2026-09-08 18:09:30 +02:00
J. Nick Koston 157d3adc0e Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-08 18:09:30 +02:00
J. Nick Koston 845416ff55 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-08 18:09:30 +02:00
J. Nick Koston e3f46f0572 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-08 18:09:29 +02:00
J. Nick Koston 5f8d620ed8 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-08 18:09:29 +02:00
J. Nick Koston 7b6cff8adb Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-08 18:09:29 +02:00
J. Nick Koston a034800d91 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-08 18:09:29 +02:00
J. Nick Koston 5995887e7a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-08 18:09:28 +02:00
J. Nick Koston d6c337f9e0 Merge remote-tracking branch 'origin/host-pch' into host-pch 2026-09-08 18:09:27 +02:00
J. Nick Koston ff05946f33 Merge remote-tracking branch 'origin/pch-strict-ci' into pch-strict-ci 2026-09-08 18:09:27 +02:00
J. Nick Koston 5038755210 Merge remote-tracking branch 'origin/platformio-pch-libretiny' into platformio-pch-libretiny 2026-09-08 18:09:27 +02:00
J. Nick Koston 439f873767 Merge remote-tracking branch 'origin/platformio-pch-rp2' into platformio-pch-rp2 2026-09-08 18:09:27 +02:00
J. Nick Koston 9406d94dad Merge remote-tracking branch 'origin/esp32-idf-pch' into esp32-idf-pch 2026-09-08 18:09:27 +02:00
J. Nick Koston 7563e64482 Merge remote-tracking branch 'origin/esp8266-native-build-spec' into esp8266-native-build-spec 2026-09-08 18:09:26 +02:00
J. Nick Koston d941d910cc Merge remote-tracking branch 'origin/esp8266-native-pch' into esp8266-native-pch 2026-09-08 18:09:26 +02:00
J. Nick Koston 95ca13fba0 Merge remote-tracking branch 'origin/esp8266-arduino-toolchain' into esp8266-arduino-toolchain 2026-09-08 18:09:26 +02:00
J. Nick Koston e31a1b2324 Merge remote-tracking branch 'origin/esp8266-native-ninja-emission' into esp8266-native-ninja-emission 2026-09-08 18:09:26 +02:00
J. Nick Koston 9f3f028b9d Merge branch 'pch-strict-ci' into host-pch 2026-09-08 18:02:33 +02:00
J. Nick Koston ba7b5262f4 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-08 18:02:32 +02:00
J. Nick Koston 2522e434b6 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-08 18:02:32 +02:00
J. Nick Koston 52ffd304ef Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-08 18:02:32 +02:00
J. Nick Koston b46bfc9bc3 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-08 18:02:31 +02:00
J. Nick Koston 79aab2c700 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-08 18:02:31 +02:00
J. Nick Koston 25dc7edca0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-08 18:02:31 +02:00
J. Nick Koston f629b9fee9 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-08 18:02:28 +02:00
J. Nick Koston 4557c7f0e8 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-08 18:02:15 +02:00
J. Nick Koston a176929805 Merge branch 'pch-strict-ci' into host-pch 2026-09-08 18:01:53 +02:00
J. Nick Koston 6a2a685bc7 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-08 18:01:52 +02:00
J. Nick Koston c1cb889f62 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-08 18:01:52 +02:00
J. Nick Koston 992789ba02 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-08 18:01:52 +02:00
J. Nick Koston 81ec1c999c Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-08 18:01:52 +02:00
J. Nick Koston 16081633dc Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-08 18:01:51 +02:00
J. Nick Koston bcdb87aaf8 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-09-08 18:01:51 +02:00
J. Nick Koston a4a5100942 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-08 18:01:51 +02:00
J. Nick Koston e79ea0aa4b Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-08 18:01:50 +02:00
J. Nick Koston bc1c91a5f7 Merge branch 'pch-strict-ci' into host-pch 2026-09-03 23:48:53 +02:00
J. Nick Koston e2229f1a5e Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-03 23:48:53 +02:00
J. Nick Koston f99b95e9a2 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-03 23:48:53 +02:00
J. Nick Koston 2b7f5f0ea9 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-03 23:48:52 +02:00
J. Nick Koston f5859f020b Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-03 23:48:52 +02:00
J. Nick Koston 5184cc1ace Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-03 23:48:52 +02:00
J. Nick Koston a59ab05bc8 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-09-03 23:48:38 +02:00
J. Nick Koston 71f9c159a8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-03 23:46:48 +02:00
J. Nick Koston 417e1793c6 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-03 23:46:42 +02:00
J. Nick Koston b81d250737 Merge branch 'pch-strict-ci' into host-pch 2026-09-02 11:18:09 +02:00
J. Nick Koston 85b03d9dc1 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-09-02 11:18:09 +02:00
J. Nick Koston 8639526e5f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-09-02 11:18:08 +02:00
J. Nick Koston 95fd6c42f3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-09-02 11:18:08 +02:00
J. Nick Koston 42761a66b4 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-09-02 11:18:07 +02:00
J. Nick Koston bbd66c61da Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-09-02 11:18:07 +02:00
J. Nick Koston a5a3163b5d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	tests/script/test_determine_jobs.py
2026-09-02 11:17:59 +02:00
J. Nick Koston e547af259e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-09-02 11:17:14 +02:00
J. Nick Koston 0f05adbb4f Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-09-02 11:17:14 +02:00
J. Nick Koston cdd89dbfed Merge branch 'pch-strict-ci' into host-pch 2026-08-30 14:57:41 -05:00
J. Nick Koston 59367c9c44 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-30 14:57:40 -05:00
J. Nick Koston 2a41f7e2a8 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-30 14:57:40 -05:00
J. Nick Koston 9ef69d1576 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-30 14:57:40 -05:00
J. Nick Koston 4a7bd2d2e9 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-30 14:57:40 -05:00
J. Nick Koston 60a2bdb935 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-30 14:57:39 -05:00
J. Nick Koston 2a860769ce Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-30 14:57:39 -05:00
J. Nick Koston da95a657e1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-30 14:57:39 -05:00
J. Nick Koston ab680c2849 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-08-30 14:57:39 -05:00
J. Nick Koston 150f0a3b6c Merge branch 'pch-strict-ci' into host-pch 2026-08-28 20:52:39 -05:00
J. Nick Koston cf8872344b Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-28 20:52:39 -05:00
J. Nick Koston 6dc37ffe86 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-28 20:52:39 -05:00
J. Nick Koston f528758c8a Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-28 20:52:39 -05:00
J. Nick Koston d1704cabb2 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-28 20:52:39 -05:00
J. Nick Koston de3e4430d3 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-28 20:52:38 -05:00
J. Nick Koston b1d359c4a9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-28 20:52:38 -05:00
J. Nick Koston f3d6bc89a4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-28 20:52:38 -05:00
J. Nick Koston 4f653a195a Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-08-28 20:52:38 -05:00
J. Nick Koston 4af285a5a0 Merge branch 'pch-strict-ci' into host-pch 2026-08-28 20:45:04 -05:00
J. Nick Koston e43d2f71f4 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-28 20:45:04 -05:00
J. Nick Koston 741e436d2c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-28 20:45:04 -05:00
J. Nick Koston 34c54e4dce Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-28 20:45:03 -05:00
J. Nick Koston 0d75e3e028 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-28 20:45:03 -05:00
J. Nick Koston d0a66d26fd Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-28 20:45:03 -05:00
J. Nick Koston 22f4adbb45 Keep espidf-only infra out of the esp8266 native trigger set
The dev merge moved the ESP-IDF trigger constants into clang_tidy_hash;
the esp8266 set keeps its explicit shared-module list with a subset
tripwire against the imported set instead of unioning it wholesale.
2026-08-28 20:44:53 -05:00
J. Nick Koston f2ee227070 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	script/determine-jobs.py
2026-08-28 20:44:18 -05:00
J. Nick Koston ad92a56f07 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-28 20:43:17 -05:00
J. Nick Koston 6cbb9a61a9 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-08-28 20:43:16 -05:00
J. Nick Koston 168d96d9f4 Merge branch 'pch-strict-ci' into host-pch 2026-08-28 20:41:32 -05:00
J. Nick Koston e6dfdc8009 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-28 20:41:32 -05:00
J. Nick Koston 4b43c026f0 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-28 20:41:32 -05:00
J. Nick Koston 0f6309bc92 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-28 20:41:32 -05:00
J. Nick Koston d1b28124bc Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-28 20:41:31 -05:00
J. Nick Koston a817a01097 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-28 20:41:31 -05:00
J. Nick Koston de60f9730e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-28 20:41:31 -05:00
J. Nick Koston e4ca495c4f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-28 20:41:31 -05:00
J. Nick Koston 77d326a662 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-08-28 20:41:30 -05:00
J. Nick Koston 94fc9ec63a Merge branch 'pch-strict-ci' into host-pch 2026-08-28 13:52:01 -05:00
J. Nick Koston 340ac06699 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-28 13:52:01 -05:00
J. Nick Koston 455b14e10f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-28 13:52:01 -05:00
J. Nick Koston 9e995377d5 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-28 13:52:01 -05:00
J. Nick Koston ade078a7f6 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-28 13:52:00 -05:00
J. Nick Koston 5f273cef7f Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-28 13:52:00 -05:00
J. Nick Koston 9f3842a0e0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-28 13:52:00 -05:00
J. Nick Koston 36e38125c6 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-28 13:51:59 -05:00
J. Nick Koston 6e8109b99c Merge remote-tracking branch 'origin/dev' into esp8266-native-build-spec 2026-08-28 13:51:59 -05:00
J. Nick Koston e51f711883 Merge branch 'pch-strict-ci' into host-pch 2026-08-28 13:07:06 -05:00
J. Nick Koston ece74ee0d1 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-28 13:07:06 -05:00
J. Nick Koston 7a947cd4c9 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-28 13:07:06 -05:00
J. Nick Koston 40f548a529 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-28 13:07:06 -05:00
J. Nick Koston 7e20e497bd Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-28 13:07:05 -05:00
J. Nick Koston 4137511f81 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-28 13:07:05 -05:00
J. Nick Koston eb1a3bc9e4 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-28 13:07:05 -05:00
J. Nick Koston 0a595aab03 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-28 13:07:05 -05:00
J. Nick Koston 9cefbd1901 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-28 13:07:04 -05:00
J. Nick Koston b1a048e27d Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-28 13:07:04 -05:00
J. Nick Koston addcb472af Merge branch 'pch-strict-ci' into host-pch 2026-08-27 23:01:19 -05:00
J. Nick Koston 4ecbde8bbc Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-27 23:01:19 -05:00
J. Nick Koston 9794eb9fc2 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-27 23:01:18 -05:00
J. Nick Koston fc41843cd5 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-27 23:01:18 -05:00
J. Nick Koston 0d50b57414 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-27 23:01:18 -05:00
J. Nick Koston 880ffc609d Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-27 23:01:18 -05:00
J. Nick Koston 979aac1cae Silence the framework elf2bin script's SyntaxWarning
The bundled elf2bin.py uses unescaped regex strings that Python 3.12+
flags at compile time; the frozen 3.1.2 framework will never fix it,
so the ninja rule suppresses that category for the one invocation.
2026-08-27 23:01:15 -05:00
J. Nick Koston b5c78a4711 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 15:53:00 -05:00
J. Nick Koston a114147e03 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-27 15:53:00 -05:00
J. Nick Koston 80b592fa16 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-27 15:52:59 -05:00
J. Nick Koston 665f1d46ca Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-27 15:52:59 -05:00
J. Nick Koston 5f97c5756b Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-27 15:52:59 -05:00
J. Nick Koston 95ea16b8c4 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-27 15:52:59 -05:00
J. Nick Koston b29b203ab1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-27 15:52:58 -05:00
J. Nick Koston a928609b72 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-27 15:52:58 -05:00
J. Nick Koston eb44311bb3 Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-27 15:52:58 -05:00
J. Nick Koston 31470e7997 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-27 15:52:58 -05:00
J. Nick Koston 5bc3102c82 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 14:04:02 -05:00
J. Nick Koston a5e4882196 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-27 14:04:02 -05:00
J. Nick Koston 4f9a02f85a Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-27 14:04:02 -05:00
J. Nick Koston 8f1e581bf6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-27 14:04:02 -05:00
J. Nick Koston 8f8e6e95d4 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-27 14:04:02 -05:00
J. Nick Koston c817bdd25e Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-27 14:04:02 -05:00
J. Nick Koston 238238e8a1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-27 14:04:01 -05:00
J. Nick Koston 7288a70f96 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-27 14:04:01 -05:00
J. Nick Koston a1576fe28a Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-27 14:04:01 -05:00
J. Nick Koston 7f77764dbb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-27 14:04:01 -05:00
J. Nick Koston c4c6fe198e Merge branch 'pch-strict-ci' into host-pch 2026-08-27 12:38:39 -05:00
J. Nick Koston 7850fba837 Merge branch 'platformio-pch-libretiny' into pch-strict-ci 2026-08-27 12:38:39 -05:00
J. Nick Koston c2eb877a17 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-27 12:38:32 -05:00
J. Nick Koston 72c670f5f1 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-27 12:38:31 -05:00
J. Nick Koston ecc9248426 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-27 12:38:31 -05:00
J. Nick Koston 9d3a68cd33 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-27 12:38:31 -05:00
J. Nick Koston bb823ba4c0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-27 12:38:24 -05:00
J. Nick Koston 6d4a7e0a48 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-27 12:38:24 -05:00
J. Nick Koston b866a1f4a4 Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-27 12:38:24 -05:00
J. Nick Koston 1132ec92e8 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-27 12:38:24 -05:00
J. Nick Koston e56edc4af0 Drop the relative-path branch; compile databases record absolute paths 2026-08-27 12:37:01 -05:00
J. Nick Koston c6b1a41e76 Match the pch source TU by resolved path so symlinked build dirs keep the pch 2026-08-27 12:31:53 -05:00
J. Nick Koston 41d68d2978 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 09:40:58 -05:00
J. Nick Koston 59556a730d Keep the parity test hermetic, give touch the shared error contract 2026-08-27 09:40:54 -05:00
J. Nick Koston 7d4e28b5e2 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 09:13:55 -05:00
J. Nick Koston 87cbe42cae Blame the baseline honestly, split sidecar unlinks, pin the script's knob and import branches 2026-08-27 09:13:51 -05:00
J. Nick Koston 8180134d30 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 08:40:39 -05:00
J. Nick Koston 8a5d53899c Simplify: strict knob via parse_enable_env, one probe tail, latch folded into _fail, discard owns its policy 2026-08-27 08:40:35 -05:00
J. Nick Koston 92b71f8ce4 Exclude the prefix wrapper from esphome.h, state the failure-path cost honestly 2026-08-27 08:33:25 -05:00
J. Nick Koston 4605ac08a5 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 08:32:13 -05:00
J. Nick Koston 3e5688d6cd Blame the pch only when a baseline passes, validate the strict knob, abort on an undiscardable stale header 2026-08-27 08:32:01 -05:00
J. Nick Koston 9580fd14da Merge branch 'pch-strict-ci' into host-pch 2026-08-27 00:40:42 -05:00
J. Nick Koston d38542e48b Escalate all strict consumers, keep cached-probe rejections unlatched, drop the dead probe knob 2026-08-27 00:40:37 -05:00
J. Nick Koston 364c530832 Merge branch 'pch-strict-ci' into host-pch 2026-08-27 00:26:00 -05:00
J. Nick Koston c89c2d975d Strict escalates consumer invalid-pch, re-probes cached headers everywhere, and defaults the matrix to strict 2026-08-27 00:25:38 -05:00
J. Nick Koston a0c3a010e4 Guard the prefix for C edges, gate it on the pch knob, pin its resolution 2026-08-27 00:21:14 -05:00
J. Nick Koston fd871b8898 Precompile a curated core-header prefix on host 2026-08-27 00:10:07 -05:00
J. Nick Koston 78eff4f485 Strict re-probes a cached .gch, probe diagnostics get the exit-code fallback, nobuild detection narrows to ImportError 2026-08-26 23:43:09 -05:00
J. Nick Koston 833af674bf Simplify: shared tool-step runner, probe args helper, buildtool touch stamp, knob-spelling parity 2026-08-26 23:20:06 -05:00
J. Nick Koston 15d4f187c7 Bake the probe stamp into the rule text; edge bindings cannot expand $out 2026-08-26 23:10:55 -05:00
J. Nick Koston 21643396c4 Add an esp8266 native-toolchain smoke entry to the strict compile matrix 2026-08-26 23:03:00 -05:00
J. Nick Koston 34daa6138a Probe failures follow the compile branch's transient rules, strict on the native esp8266 job 2026-08-26 23:02:18 -05:00
J. Nick Koston 0266b7f0fb Cover the probe spawn failure and both probe-edge flag branches 2026-08-26 22:55:52 -05:00
J. Nick Koston 5d690104b5 Strict fails on a disabled pch, narrows the projenv exemption, and covers the new funnel sites 2026-08-26 22:51:53 -05:00
J. Nick Koston 4a3b095172 Probe the built .gch on the native paths so strict CI reds on an unloadable pch 2026-08-26 22:47:42 -05:00
J. Nick Koston 54bff55642 Reraise in strict through the IDF flow, funnel the remaining degrade paths, exempt nobuild 2026-08-26 22:42:03 -05:00
J. Nick Koston 264ccc0989 Add ESPHOME_PCH_STRICT and enforce it in the esp8266/esp32/rp2 image compile tests 2026-08-26 22:29:53 -05:00
J. Nick Koston 7449623022 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 22:23:01 -05:00
J. Nick Koston 2eab26052a Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 22:22:58 -05:00
J. Nick Koston 96beeed2c2 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 22:22:55 -05:00
J. Nick Koston 85142b5b99 Pass -MF to the probe only alongside a dependency flag 2026-08-26 22:22:42 -05:00
J. Nick Koston 1e13390b6d Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 22:06:04 -05:00
J. Nick Koston c916e93988 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 22:06:04 -05:00
J. Nick Koston 3ecd4e3e69 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 22:06:04 -05:00
J. Nick Koston a5afa55122 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch
# Conflicts:
#	esphome/platformio/toolchain.py
2026-08-26 22:06:01 -05:00
J. Nick Koston 3439a2d5ca Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-26 22:05:33 -05:00
J. Nick Koston c2f8347eed Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-26 22:05:32 -05:00
J. Nick Koston 6767e43022 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-26 22:05:32 -05:00
J. Nick Koston 178ff2c3ef Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-26 22:05:10 -05:00
J. Nick Koston 3e3655036b Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 14:23:26 -05:00
J. Nick Koston 58d6aec7fd Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 14:23:23 -05:00
J. Nick Koston c97250508a Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 14:23:20 -05:00
J. Nick Koston 3dd608cffc Use a drive-qualified basedir in the test on Windows 2026-08-26 14:23:16 -05:00
J. Nick Koston 16e4e05d92 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 14:14:08 -05:00
J. Nick Koston 153bfbc47c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 14:14:05 -05:00
J. Nick Koston 50c9a3a5bb Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 14:14:02 -05:00
J. Nick Koston 1d4d28832e Reject relative CCACHE_BASEDIR values too 2026-08-26 14:13:57 -05:00
J. Nick Koston c5d14b9423 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 13:21:30 -05:00
J. Nick Koston 694741cd6b Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 13:21:28 -05:00
J. Nick Koston 1719e75e57 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 13:21:25 -05:00
J. Nick Koston 26e51c23b1 Hoist is_joined_include, cover the falsy EXTSUM warning 2026-08-26 13:21:21 -05:00
J. Nick Koston c2d1b1c583 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 13:14:22 -05:00
J. Nick Koston 198e4abc5d Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 13:14:17 -05:00
J. Nick Koston 35ab90fc58 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 13:14:11 -05:00
J. Nick Koston 6530bb62f8 Stat-aware local walk, atomic flag+env application, guard degenerate basedir and -include- flags 2026-08-26 13:14:03 -05:00
J. Nick Koston 77fc8af9f0 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 11:59:22 -05:00
J. Nick Koston b8675a4b56 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 11:59:18 -05:00
J. Nick Koston b497ff17a7 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 11:58:36 -05:00
J. Nick Koston 3730f7bbae Distinguish stat failure from absence, fail closed on unmodelable flags and unreadable local headers 2026-08-26 11:58:20 -05:00
J. Nick Koston f4199a7510 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 10:44:37 -05:00
J. Nick Koston c7f0e17409 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 10:44:35 -05:00
J. Nick Koston 0ba8e3d83e Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 10:44:32 -05:00
J. Nick Koston d0263b0bef Mirror the joined -include fold, harden the probe, fail closed on unreadable closure headers 2026-08-26 10:44:17 -05:00
J. Nick Koston c6d056b240 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 10:03:33 -05:00
J. Nick Koston ca81777eba Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 10:03:31 -05:00
J. Nick Koston 68f2dc3219 Gate the ccache sloppiness on emission for the IDF backend too 2026-08-26 10:03:26 -05:00
J. Nick Koston c7fb26a6d1 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 10:01:27 -05:00
J. Nick Koston 410a3868ea Gate the ccache sloppiness on the pch actually being emitted 2026-08-26 10:00:59 -05:00
J. Nick Koston f665ecf977 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 09:58:06 -05:00
J. Nick Koston 5e95306bcc Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 09:58:02 -05:00
J. Nick Koston c813fe8e35 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 09:57:59 -05:00
J. Nick Koston a69f2c8f66 Fold the joined src force-include spelling, export ccache settings after the flags land 2026-08-26 09:57:44 -05:00
J. Nick Koston c025b875d1 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 09:34:43 -05:00
J. Nick Koston 6a5a092f03 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 09:34:41 -05:00
J. Nick Koston c10fb88430 Trim comments to repo standard 2026-08-26 09:34:37 -05:00
J. Nick Koston 5be8ad98e8 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 09:33:15 -05:00
J. Nick Koston c9b4086a92 Trim comments and docstrings to repo standard 2026-08-26 09:33:06 -05:00
J. Nick Koston 639e1c2fdf Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 09:08:08 -05:00
J. Nick Koston 6722ec22ab Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 09:08:05 -05:00
J. Nick Koston 3d35a111ac Pin the compile locale in the generic pch flow too 2026-08-26 09:08:02 -05:00
J. Nick Koston a07bdf3a03 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 09:07:56 -05:00
J. Nick Koston 397ae10c55 Demote invalid-pch on PlatformIO too, pin the compile locale, document the .sum invariant 2026-08-26 09:07:38 -05:00
J. Nick Koston e2446cad8f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 08:40:41 -05:00
J. Nick Koston 404cf7b728 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 08:40:38 -05:00
J. Nick Koston 987da8f5c4 Treat resource exhaustion as transient in the generic pch flow too 2026-08-26 08:40:35 -05:00
J. Nick Koston c9963881ba Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 08:39:47 -05:00
J. Nick Koston 7417dcdd7b Demote invalid-pch under user -Werror, catch the joined -include spelling, treat resource exhaustion as transient 2026-08-26 08:39:27 -05:00
J. Nick Koston 2a7245ac79 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 00:46:51 -05:00
J. Nick Koston 1ca8b7066c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 00:46:48 -05:00
J. Nick Koston e13aa8b775 Read the pch sidecars defensively in the generic flow too 2026-08-26 00:46:45 -05:00
J. Nick Koston 3a483e3284 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 00:46:31 -05:00
J. Nick Koston f5593deb38 Warn and skip the pch when a user -include precedes it, walk angle includes, read sidecars defensively 2026-08-26 00:46:14 -05:00
J. Nick Koston 0fea10f263 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-26 00:06:44 -05:00
J. Nick Koston f8f12b3a5d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-26 00:06:43 -05:00
J. Nick Koston 187199e9b3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-26 00:06:43 -05:00
J. Nick Koston fb5a042dfe Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-26 00:06:43 -05:00
J. Nick Koston 85dd29f7e0 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-26 00:06:43 -05:00
J. Nick Koston 21896b057f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-26 00:06:42 -05:00
J. Nick Koston d651573a20 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-26 00:06:42 -05:00
J. Nick Koston 0e404ba2b4 Update ar prose to match the rcs/qs ops 2026-08-26 00:06:28 -05:00
J. Nick Koston a892f47f89 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 23:42:31 -05:00
J. Nick Koston 9fa031f134 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 23:42:31 -05:00
J. Nick Koston c9044bb860 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 23:42:30 -05:00
J. Nick Koston b255e77e76 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 23:42:30 -05:00
J. Nick Koston c2767c096c Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 23:42:30 -05:00
J. Nick Koston c86b038dc1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 23:42:30 -05:00
J. Nick Koston 79a72efee7 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 23:42:30 -05:00
J. Nick Koston 21fd74b201 Tighten the review-round edges
Only IncompatiblePlatform counts as a knowing skip; other malformed
manifest data stays out of the satisfied set so the reconciliation can
still flag a broken promise. Backend-provided names are recorded before
the manifest-name evidence so the overlap warns once, in the backend's
own suppression loop. ar runs rcs/qs so the symbol index is explicit,
and the copy shim prints and returns 1 like its siblings instead of
re-raising.
2026-08-25 23:42:13 -05:00
J. Nick Koston bffbc6dce5 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 23:16:53 -05:00
J. Nick Koston ba9131324a Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 23:16:53 -05:00
J. Nick Koston 5ab40084c9 Merge remote-tracking branch 'origin/platformio-pch-libretiny' into platformio-pch-libretiny 2026-08-25 23:16:53 -05:00
J. Nick Koston 82b9575b6f Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 23:16:52 -05:00
J. Nick Koston 55f1122eba Merge remote-tracking branch 'origin/esp8266-native-pch' into esp8266-native-pch 2026-08-25 23:16:52 -05:00
J. Nick Koston 6223ecda32 Merge remote-tracking branch 'origin/platformio-pch-rp2' into platformio-pch-rp2 2026-08-25 23:16:52 -05:00
J. Nick Koston 5bd7884ac1 Merge remote-tracking branch 'origin/esp32-idf-pch' into esp32-idf-pch 2026-08-25 23:16:52 -05:00
J. Nick Koston c1c78ebf18 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 23:16:33 -05:00
J. Nick Koston dd05cdd2f8 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 23:16:33 -05:00
J. Nick Koston cfcbf5b420 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 23:16:33 -05:00
J. Nick Koston fb640bdc47 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 23:16:32 -05:00
J. Nick Koston 7aa90fc4c4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 23:16:32 -05:00
J. Nick Koston a75d6768ab Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 23:16:32 -05:00
J. Nick Koston 20e5b23b86 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 23:16:32 -05:00
J. Nick Koston b957fb0712 Keep the missing-manifest diagnostic at debug
The legacy manifest-less layout is legal and the 3.1.2 core ships one
such library (FSTools), so the warning would be unactionable noise; a
test now pins the level.
2026-08-25 23:16:18 -05:00
J. Nick Koston 80206fd232 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 23:03:16 -05:00
J. Nick Koston e18bcc74f3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 23:03:13 -05:00
J. Nick Koston 40f74815f0 Widen the identity-unknown guard to UnicodeError in the generic prepare_pch 2026-08-25 23:03:11 -05:00
J. Nick Koston eb28f2630a Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 23:02:56 -05:00
J. Nick Koston 10204c6bd9 Surrogateescape the digest extras, keep absolute force-includes consumer-only 2026-08-25 23:02:43 -05:00
J. Nick Koston 5b53eb9f6c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:55:24 -05:00
J. Nick Koston 0768a1c8cf Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:55:24 -05:00
J. Nick Koston 32c1125116 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:55:24 -05:00
J. Nick Koston 8e5d72a133 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:55:24 -05:00
J. Nick Koston ccaec42798 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:55:23 -05:00
J. Nick Koston 5755e47101 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:55:23 -05:00
J. Nick Koston 15b9f3897b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:55:23 -05:00
J. Nick Koston aa87ab6d0d Warn when a bundled library has no manifest
Core libraries all ship one, so an absent manifest most likely means a
torn framework extraction; at debug the miscompile risk was invisible.
2026-08-25 22:55:21 -05:00
J. Nick Koston 5cd9e77f3d Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:53:03 -05:00
J. Nick Koston 5a05184ee3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:53:03 -05:00
J. Nick Koston a9284c7d4b Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:53:03 -05:00
J. Nick Koston 5a1f3a382d Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:53:02 -05:00
J. Nick Koston 813008200c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:53:02 -05:00
J. Nick Koston f217ab18d2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:53:02 -05:00
J. Nick Koston ce909f68b3 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:53:02 -05:00
J. Nick Koston 3fa4d478e5 Fail by name on a corrupt bundled manifest; name the recording side effect
A truncated bundled library.json now raises the module's named error
with the clean-all hint instead of a raw JSONDecodeError. The renamed
_reconcile_versionless_skips advertises that it records into
backend.provided_requests. Two real-converter tests gain the
registry-guard patch their siblings use so a regression fails offline.
2026-08-25 22:52:39 -05:00
J. Nick Koston 53a3501bdc Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:40:46 -05:00
J. Nick Koston bcdefa873b Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:40:46 -05:00
J. Nick Koston 6c86c02769 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:40:46 -05:00
J. Nick Koston 83eede0d9d Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:40:46 -05:00
J. Nick Koston 32c3bf7f15 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:40:46 -05:00
J. Nick Koston f21310d517 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:40:45 -05:00
J. Nick Koston 3b77d812a3 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:40:45 -05:00
J. Nick Koston 112868414e Keep per-file resolve(): srcFilter patterns may escape src_dir 2026-08-25 22:40:14 -05:00
J. Nick Koston 9304661da3 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:39:45 -05:00
J. Nick Koston fe95bd2d0c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:39:45 -05:00
J. Nick Koston 2a45a21ad3 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:39:45 -05:00
J. Nick Koston df8fb0fb49 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:39:45 -05:00
J. Nick Koston 1895bef123 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:39:44 -05:00
J. Nick Koston e18e8deded Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:39:44 -05:00
J. Nick Koston de1bb32262 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:39:44 -05:00
J. Nick Koston 2497e1aa94 Simplify the library backend after review
Rely on normalize_dependencies' guarantee of a non-empty string name
instead of re-checking it, collect sources in a single pass that
re-roots on the resolved directory rather than calling realpath per
file, probe library.properties once, hoist the invariant log-level
choice out of the warning loop, and record provided_requests as a set
since order was never used.
2026-08-25 22:39:40 -05:00
J. Nick Koston 85d49bd940 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:29:40 -05:00
J. Nick Koston 36062184a1 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:29:40 -05:00
J. Nick Koston 2864ea8c9a Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:29:40 -05:00
J. Nick Koston bf849f441f Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:29:40 -05:00
J. Nick Koston 97bf416a2b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:29:39 -05:00
J. Nick Koston d3d81f593b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:29:39 -05:00
J. Nick Koston 5d57bb7781 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:29:39 -05:00
J. Nick Koston fbb13f6fc9 Trim comments to repo standard 2026-08-25 22:29:35 -05:00
J. Nick Koston 5f81a04086 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:23:08 -05:00
J. Nick Koston ac176636db Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:23:08 -05:00
J. Nick Koston aebcc71201 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:23:07 -05:00
J. Nick Koston fc654c4c63 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:23:07 -05:00
J. Nick Koston 204cec24a1 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:23:07 -05:00
J. Nick Koston d87e666f02 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:23:07 -05:00
J. Nick Koston 2c67bb965a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:23:06 -05:00
J. Nick Koston 6cdc34178d Reconcile provides() promises against the final manifests only
The walk records across re-resolutions, so a dependency a re-resolved
manifest no longer declares would have failed the build by name. The
reconciliation now intersects the recordings with the dependency names
of the manifests actually emitted, keeping the raise for real broken
promises. The manifest-name warning also gains the treeless-backend
gate its sibling got, since those backends cannot act on it either.
2026-08-25 22:22:48 -05:00
J. Nick Koston 68ba1b9a7f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 22:04:06 -05:00
J. Nick Koston 63e6f9bf70 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 22:04:06 -05:00
J. Nick Koston daccadca3f Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 22:04:06 -05:00
J. Nick Koston 3e9b6b0355 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 22:04:06 -05:00
J. Nick Koston 5b2670ea4f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 22:04:05 -05:00
J. Nick Koston 706e3a1a39 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 22:04:05 -05:00
J. Nick Koston 853abc20ad Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 22:04:05 -05:00
J. Nick Koston bdbdaa7ddc Reconcile version-less provides() skips and quiet the drop warning for treeless backends
A version-less dependency the walk skips on the backend's promise is now
recorded like the versioned path, and a bundled candidate the backend
knowingly skips through the platform filter counts as satisfied, so the
post-emit reconciliation covers both paths without raising on legitimate
builds. The manifest-name warning deduplicates like its sibling, the
final drop warning stays at debug for backends without provides() since
they can never supply a bundled name, and a bundled library missing both
manifests leaves a debug trace instead of silently building on defaults.
2026-08-25 22:03:47 -05:00
J. Nick Koston f4a5671445 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 21:45:12 -05:00
J. Nick Koston 2beabb2ca3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 21:45:09 -05:00
J. Nick Koston d2c2414425 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 21:45:06 -05:00
J. Nick Koston 5a8e6761cb Fold only src-resolvable force-includes, surrogateescape the digest names, harden flag lexing and failure reporting 2026-08-25 21:44:52 -05:00
J. Nick Koston c6f21e2447 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 21:33:57 -05:00
J. Nick Koston 06556ceac5 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 21:33:56 -05:00
J. Nick Koston 9be7585000 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 21:33:56 -05:00
J. Nick Koston b253f32788 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 21:33:56 -05:00
J. Nick Koston 9db1835c40 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 21:33:56 -05:00
J. Nick Koston fc23fe5229 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 21:33:55 -05:00
J. Nick Koston 2e95fcf037 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 21:33:55 -05:00
J. Nick Koston d1845fcded Route extra-script link flags and fail loudly on an unfulfilled provides() promise
Extra-script LINKFLAGS travel outside build.flags by design; the backend
now drains them into the library's link flags, matching the ESP-IDF
backend, instead of dropping a link-stage input silently. An unfulfilled
provides() promise raises by name (deduplicated) like the module's other
can-never-link checks, the vacuous end-to-end silence test is replaced
by a link-flags test that can fail, and a version-less dependency
assumed satisfied by manifest name alone warns like its backend twin
since the match is name-only evidence.
2026-08-25 21:33:38 -05:00
J. Nick Koston 80c9ccd657 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:56:19 -05:00
J. Nick Koston c405d94f45 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:56:16 -05:00
J. Nick Koston f4003969ba Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 20:56:13 -05:00
J. Nick Koston 73cc3af130 Union sloppiness tokens on the PlatformIO path too, survive non-UTF-8 include names 2026-08-25 20:56:00 -05:00
J. Nick Koston 0194e2349c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:48:39 -05:00
J. Nick Koston cf2ddde04c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:48:37 -05:00
J. Nick Koston 365dcba506 Skip compile-DB entries with null fields instead of raising 2026-08-25 20:48:28 -05:00
J. Nick Koston 565ffad6f4 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:43:51 -05:00
J. Nick Koston 2145f50bb5 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:43:48 -05:00
J. Nick Koston a7e4cf536b Drop duplicate ccache test, keep full compiler output at debug, guard empty compile-DB directory 2026-08-25 20:43:37 -05:00
J. Nick Koston 62f8451831 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:40:38 -05:00
J. Nick Koston 120ac5e516 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:40:35 -05:00
J. Nick Koston eaa63e2695 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 20:40:32 -05:00
J. Nick Koston 6aa5540ff8 Cite esphome#8693 for the intended Arduino.h visibility 2026-08-25 20:40:20 -05:00
J. Nick Koston 259824d13d Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:26:29 -05:00
J. Nick Koston daf273b650 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:26:29 -05:00
J. Nick Koston faa93cc6e9 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 20:26:29 -05:00
J. Nick Koston 2e7aa4d534 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 20:26:28 -05:00
J. Nick Koston 26d7a75352 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 20:26:28 -05:00
J. Nick Koston 21febc49a2 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 20:26:28 -05:00
J. Nick Koston b5dd3d00b8 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 20:26:28 -05:00
J. Nick Koston 44d627f781 Merge remote-tracking branch 'origin/dev' into esp8266-native-library-backend 2026-08-25 20:26:27 -05:00
J. Nick Koston 90c804886d Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 20:00:39 -05:00
J. Nick Koston e6e738775b Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 20:00:37 -05:00
J. Nick Koston 791020f778 Merge follow-through: discard the pch when its identity cannot be established 2026-08-25 20:00:27 -05:00
J. Nick Koston 0c5cad19dc Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 19:59:34 -05:00
J. Nick Koston c419fc4bbc Skip the pch when a header identity is unknown, union missing sloppiness tokens, report projenv import failures 2026-08-25 19:59:25 -05:00
J. Nick Koston c15bafacfb Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 19:24:00 -05:00
J. Nick Koston 7bd2dd944c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 19:23:58 -05:00
J. Nick Koston 84028e787a Log the pch line only when true, fail closed on unreadable sdkconfig, treat signal-killed compiles as transient 2026-08-25 19:23:49 -05:00
J. Nick Koston 5d745f0605 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 19:08:39 -05:00
J. Nick Koston 5672302b01 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 19:08:37 -05:00
J. Nick Koston 9faddeb0bc Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 19:08:34 -05:00
J. Nick Koston 9636717b32 Warn on unresolvable force-includes and pch_defines-less sloppiness, vary the unreadable marker 2026-08-25 19:08:21 -05:00
J. Nick Koston e25ffaf017 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:55:03 -05:00
J. Nick Koston 80b62ceacc Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:55:00 -05:00
J. Nick Koston 81bca96e1b Run the gch compile from its resolution dir, self-clean when disabled, log the opt-out hint, pin the knob in tests 2026-08-25 18:54:48 -05:00
J. Nick Koston 256457384c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:20:37 -05:00
J. Nick Koston e5c6720063 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 18:20:36 -05:00
J. Nick Koston 4dc10199b9 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 18:20:36 -05:00
J. Nick Koston d5609f8dc6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:20:36 -05:00
J. Nick Koston a4dd668e69 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 18:20:36 -05:00
J. Nick Koston 5b92b381c3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 18:20:35 -05:00
J. Nick Koston ccfe3dc379 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 18:20:35 -05:00
J. Nick Koston f1ccff4aa7 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 18:20:35 -05:00
J. Nick Koston 260f9d8763 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 18:20:35 -05:00
J. Nick Koston dcb73e7300 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-infra 2026-08-25 18:20:34 -05:00
J. Nick Koston d08bb3992a Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:19:27 -05:00
J. Nick Koston 8197fcd5a1 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:19:27 -05:00
J. Nick Koston 85520f520e Merge remote-tracking branch 'origin/platformio-pch-libretiny' into platformio-pch-libretiny 2026-08-25 18:19:27 -05:00
J. Nick Koston 2dd850b990 Merge remote-tracking branch 'origin/platformio-pch-rp2' into platformio-pch-rp2 2026-08-25 18:19:27 -05:00
J. Nick Koston aee60fa48a Merge remote-tracking branch 'origin/esp8266-native-pch' into esp8266-native-pch 2026-08-25 18:19:26 -05:00
J. Nick Koston d0bbd40e3b Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 18:19:26 -05:00
J. Nick Koston 7c9e7a807d Merge remote-tracking branch 'origin/esp32-idf-pch' into esp32-idf-pch 2026-08-25 18:19:26 -05:00
J. Nick Koston b11b60dd86 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:18:24 -05:00
J. Nick Koston efeb608725 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:18:24 -05:00
J. Nick Koston 7cc53d90bd Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 18:18:23 -05:00
J. Nick Koston 7b7acf7656 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 18:18:23 -05:00
J. Nick Koston bbd3e60d5b Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 18:18:23 -05:00
J. Nick Koston e8a8226bac Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 18:18:22 -05:00
J. Nick Koston e41c4c0a99 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 18:18:22 -05:00
J. Nick Koston 9a38acaa00 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 18:18:22 -05:00
J. Nick Koston d79d713edc Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 18:18:21 -05:00
J. Nick Koston 425b3e4795 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-infra 2026-08-25 18:17:23 -05:00
J. Nick Koston 600dab7185 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:13:33 -05:00
J. Nick Koston 609d9dfab3 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:13:31 -05:00
J. Nick Koston 8118575491 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 18:13:29 -05:00
J. Nick Koston 1b54d1b5b0 Survive -t nobuild, skip library trees in the local include digest, drop the false ENV scoping claim 2026-08-25 18:13:15 -05:00
J. Nick Koston a28086547f Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:05:34 -05:00
J. Nick Koston 0cdd654cc6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:05:31 -05:00
J. Nick Koston 3e2dc30c06 Move the curated header list to build_helpers as PCH_DEFAULT_HEADERS 2026-08-25 18:05:23 -05:00
J. Nick Koston a400753d96 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 18:03:02 -05:00
J. Nick Koston 0f5050a617 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 18:03:00 -05:00
J. Nick Koston 7387211cf1 Move the generic pch build machinery into build_helpers/pch.py 2026-08-25 18:02:51 -05:00
J. Nick Koston 4819f986bc Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 17:58:31 -05:00
J. Nick Koston 904083d531 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 17:58:29 -05:00
J. Nick Koston 2a41892559 Simplify: reuse discard_pch, effective_ccache_basedir, and idedata's C++ suffixes 2026-08-25 17:58:05 -05:00
J. Nick Koston e1eff7447d Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 17:58:05 -05:00
J. Nick Koston b6c1552bcb Simplify: shared artifact names, one cxx override param, extracted gch compile, transient spawn semantics in the script 2026-08-25 17:56:23 -05:00
J. Nick Koston d8255cbece Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 17:48:14 -05:00
J. Nick Koston 6175ff24fe Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 17:48:12 -05:00
J. Nick Koston 1059ecf50c Fold header order into pch checksum, gate rebuild-forcing touch, guard malformed compile DBs 2026-08-25 17:48:01 -05:00
J. Nick Koston c5c7b598c9 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 17:45:02 -05:00
J. Nick Koston 564f3e31c1 Harden idedata -include anchoring, probe exit check, package identity, and failure diagnostics 2026-08-25 17:44:54 -05:00
J. Nick Koston 10a81076b2 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 16:20:46 -05:00
J. Nick Koston 9a2644e6e6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 16:20:43 -05:00
J. Nick Koston 743f1dcb09 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 16:20:06 -05:00
J. Nick Koston a4a8c77151 Resolve idedata force-include paths, test probe rejection and env scoping, derive clean names 2026-08-25 16:19:29 -05:00
J. Nick Koston ceac527259 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:54:05 -05:00
J. Nick Koston 0908d1d3c6 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:54:02 -05:00
J. Nick Koston 278abf2771 Treat pch spawn errors as transient, keep user force-includes, fold command into checksum 2026-08-25 15:53:54 -05:00
J. Nick Koston 408dcd353a Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:44:03 -05:00
J. Nick Koston ca9500b5a8 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:44:03 -05:00
J. Nick Koston b25e30c0b7 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 15:44:02 -05:00
J. Nick Koston c1dfecf964 Cover the partial-clean pch artifact removal 2026-08-25 15:43:18 -05:00
J. Nick Koston cce6f71076 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:38:05 -05:00
J. Nick Koston 36790f78ab Merge branch 'platformio-pch-libretiny' of https://github.com/esphome/esphome into platformio-pch-libretiny 2026-08-25 15:38:04 -05:00
J. Nick Koston f215e3f45b Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:38:03 -05:00
J. Nick Koston fcaf17dafa Merge branch 'platformio-pch-rp2' of https://github.com/esphome/esphome into platformio-pch-rp2 2026-08-25 15:38:03 -05:00
J. Nick Koston 76ed94fe28 Merge branch 'esp32-idf-pch' of https://github.com/esphome/esphome into esp32-idf-pch 2026-08-25 15:38:02 -05:00
J. Nick Koston be60eca212 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:37:16 -05:00
J. Nick Koston b24bfa7552 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:37:16 -05:00
J. Nick Koston 1b325a66ce Warn when a consumer ignores the precompiled header 2026-08-25 15:37:15 -05:00
J. Nick Koston 273e5f22db Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 15:37:03 -05:00
J. Nick Koston d08c524f19 Harden the pch script for Windows paths and make ignored pchs visible 2026-08-25 15:36:41 -05:00
pre-commit-ci-lite[bot] f198964bc5 apply automatic formatting fixes 2026-08-25 20:32:46 +00:00
pre-commit-ci-lite[bot] 6431f6da35 apply automatic formatting fixes 2026-08-25 20:32:42 +00:00
pre-commit-ci-lite[bot] 4c26f23e76 apply automatic formatting fixes 2026-08-25 20:32:17 +00:00
pre-commit-ci-lite[bot] 18eb05177b apply automatic formatting fixes 2026-08-25 20:30:53 +00:00
J. Nick Koston f438e5a19a Merge branch 'platformio-pch-libretiny' of https://github.com/esphome/esphome into platformio-pch-libretiny 2026-08-25 15:29:59 -05:00
J. Nick Koston 92233e0ff2 Merge branch 'platformio-pch-rp2' of https://github.com/esphome/esphome into platformio-pch-rp2 2026-08-25 15:29:58 -05:00
J. Nick Koston 702da28c9c Merge branch 'esp32-idf-pch' of https://github.com/esphome/esphome into esp32-idf-pch 2026-08-25 15:29:58 -05:00
J. Nick Koston 8421fe0170 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:29:16 -05:00
J. Nick Koston 91eb7f2f7c Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:29:16 -05:00
J. Nick Koston 88bcb7ff03 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 15:29:16 -05:00
J. Nick Koston 009e28998d Merge branch 'esp8266-native-pch' into platformio-pch-libretiny 2026-08-25 15:28:36 -05:00
J. Nick Koston c50a1a068c Merge branch 'esp8266-native-pch' of https://github.com/esphome/esphome into esp8266-native-pch 2026-08-25 15:28:04 -05:00
J. Nick Koston dc45cd4d3f Probe that the toolchain can load the gch before enabling the pch 2026-08-25 15:27:53 -05:00
J. Nick Koston e52af0dfa8 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:17:14 -05:00
J. Nick Koston 250c5bf606 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:17:14 -05:00
J. Nick Koston 649727fcfb Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 15:17:14 -05:00
J. Nick Koston 6c98f2a177 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 15:17:13 -05:00
J. Nick Koston bf573413c4 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 15:17:13 -05:00
J. Nick Koston c6217235e3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 15:17:13 -05:00
J. Nick Koston fa571f2881 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 15:17:12 -05:00
J. Nick Koston 26aac6619c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 15:17:12 -05:00
J. Nick Koston 659ad9fe13 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 15:17:12 -05:00
J. Nick Koston da046a9886 Assert the forced-on working-ccache case emits no warning at all
The 'Not decoded' escape hatch could only mask a regression; assert the
captured records directly instead.
2026-08-25 15:16:54 -05:00
pre-commit-ci-lite[bot] f5fd82bc42 apply automatic formatting fixes 2026-08-25 20:08:23 +00:00
J. Nick Koston 958ea20cc4 Use the shared pch registration helper 2026-08-25 15:06:29 -05:00
J. Nick Koston 243b8a871c Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 15:05:58 -05:00
J. Nick Koston 352129e77e Use the shared pch registration helper 2026-08-25 15:05:44 -05:00
J. Nick Koston e0a7347f41 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 15:05:10 -05:00
J. Nick Koston ce37667b1d Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 15:05:08 -05:00
J. Nick Koston fae9eb0dd2 Hash project-local include dirs into the pch checksum and share the registration gate 2026-08-25 15:04:55 -05:00
J. Nick Koston 0007dfab70 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 14:38:16 -05:00
J. Nick Koston 52176c4d59 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 14:38:16 -05:00
J. Nick Koston aa6e3f74fd Add the OBJECT_DEPENDS edge so a rebuilt gch recompiles its consumers 2026-08-25 14:38:04 -05:00
J. Nick Koston e0662b1551 Merge branch 'platformio-pch-rp2' into platformio-pch-libretiny 2026-08-25 14:29:11 -05:00
J. Nick Koston 61009e1162 Merge branch 'esp32-idf-pch' into platformio-pch-rp2 2026-08-25 14:29:10 -05:00
J. Nick Koston 078e918bdb Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 14:29:10 -05:00
J. Nick Koston 6ab93051b7 Address review: order-covering checksum, loud degraded states, script tests 2026-08-25 14:28:57 -05:00
J. Nick Koston d5c044c7b3 [libretiny] Enable the PlatformIO precompiled header 2026-08-25 14:23:14 -05:00
J. Nick Koston 94b02b46f4 [rp2] Enable the PlatformIO precompiled header 2026-08-25 14:23:14 -05:00
J. Nick Koston d081632c53 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 14:21:46 -05:00
J. Nick Koston 04648a8044 Merge branch 'esp32-idf-pch' of https://github.com/esphome/esphome into esp32-idf-pch 2026-08-25 14:18:56 -05:00
J. Nick Koston 21c9dd33e0 Use native separators in the pch test fixture paths 2026-08-25 14:18:46 -05:00
J. Nick Koston 7d91938b79 Reconstruct compiler argv per SCons element for the gch compile 2026-08-25 14:16:04 -05:00
J. Nick Koston ed59080f62 Tokenize SCons flags per element so spaced defines survive 2026-08-25 14:09:22 -05:00
J. Nick Koston d3f6cbe14a Patch the direct ccache probe in the usable-binary test 2026-08-25 14:06:32 -05:00
J. Nick Koston a63c5b3680 Merge branch 'esp8266-native-pch' of https://github.com/esphome/esphome into esp8266-native-pch 2026-08-25 14:04:38 -05:00
J. Nick Koston a6c4c46930 Merge branch 'esp8266-native-pch' into esp32-idf-pch
# Conflicts:
#	esphome/espidf/framework.py
2026-08-25 14:04:35 -05:00
J. Nick Koston 558acf6900 Make the PlatformIO pch script platform-agnostic 2026-08-25 14:04:29 -05:00
J. Nick Koston 32e11a95cb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 14:04:02 -05:00
J. Nick Koston 911b4afa08 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 14:04:02 -05:00
J. Nick Koston 1cb86be73d Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 14:04:02 -05:00
J. Nick Koston 2afec3db14 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 14:04:01 -05:00
J. Nick Koston 6cfff58f53 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 14:04:01 -05:00
J. Nick Koston ac458608fd Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 14:04:01 -05:00
J. Nick Koston 95ea7b954c Probe forced-on ccache directly so the warnings cannot contradict, carry the traceback on unexpected prefetch failures 2026-08-25 14:03:44 -05:00
J. Nick Koston 337ecfb8f9 Select the pch TU by source path, expand response files, and key the failure marker on the command 2026-08-25 13:58:34 -05:00
J. Nick Koston b08615f92f Merge remote-tracking branch 'origin/esp32-idf-pch' into esp32-idf-pch 2026-08-25 13:50:13 -05:00
J. Nick Koston 8625e02b8e Cover the remaining pch branches 2026-08-25 13:50:01 -05:00
J. Nick Koston f2204d155a Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 13:46:35 -05:00
J. Nick Koston f18b182606 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 13:46:34 -05:00
J. Nick Koston 43c389e1fa Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 13:46:34 -05:00
J. Nick Koston f4808e291e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 13:46:34 -05:00
J. Nick Koston cc605b1cfe Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 13:46:34 -05:00
J. Nick Koston 0239475b78 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 13:46:34 -05:00
J. Nick Koston 7d6e562bf5 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 13:46:33 -05:00
J. Nick Koston 465222a372 Cover the forced-on working-ccache path, pin both marker-probe arms 2026-08-25 13:46:16 -05:00
J. Nick Koston d46518d890 Cover the pch compile-command and failure paths 2026-08-25 13:45:43 -05:00
J. Nick Koston f866f878de Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 13:44:47 -05:00
J. Nick Koston 7f6a007d27 Add direct tests for the shared pch helpers 2026-08-25 13:44:24 -05:00
J. Nick Koston 59fc8dd2bb Merge remote-tracking branch 'origin/esp32-idf-pch' into esp32-idf-pch 2026-08-25 13:39:50 -05:00
J. Nick Koston 149d4d24a1 Merge branch 'esp8266-native-pch' into esp32-idf-pch 2026-08-25 13:39:50 -05:00
J. Nick Koston 0e54f66e78 Merge remote-tracking branch 'origin/esp8266-native-pch' into esp8266-native-pch 2026-08-25 13:39:49 -05:00
J. Nick Koston 35104faaba Merge branch 'esp8266-native-pch' into esp32-idf-pch
# Conflicts:
#	esphome/espidf/framework.py
2026-08-25 13:38:03 -05:00
J. Nick Koston c27f97b8f9 [esp32] Precompile the shared core headers for src compiles 2026-08-25 13:37:42 -05:00
J. Nick Koston de7f622983 Merge branch 'esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 13:37:27 -05:00
J. Nick Koston 986c0563b2 Merge remote-tracking branch 'origin/esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 13:36:15 -05:00
J. Nick Koston 6c15897d26 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 13:34:52 -05:00
J. Nick Koston 6a39f1509f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 13:34:52 -05:00
J. Nick Koston 0868e0839d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 13:34:51 -05:00
J. Nick Koston 43d0dd04e7 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 13:34:51 -05:00
J. Nick Koston b942c00be9 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 13:34:51 -05:00
J. Nick Koston a3194aa0f2 Split the forced-on ccache warning by cause, cover the marker re-check 2026-08-25 13:34:29 -05:00
J. Nick Koston 71cf6049aa [esp32] Precompile the shared core headers for src compiles 2026-08-25 13:33:56 -05:00
J. Nick Koston 2f1d21191e Merge remote-tracking branch 'origin/esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 13:32:52 -05:00
J. Nick Koston 83a2f78075 Walk the include closure in the pch checksum and honor a user CCACHE_BASEDIR 2026-08-25 13:32:17 -05:00
J. Nick Koston e090311ac2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 13:21:58 -05:00
J. Nick Koston 5e743ee301 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 13:21:58 -05:00
J. Nick Koston 519bc0ceb1 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 13:21:58 -05:00
J. Nick Koston 29ad72f897 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 13:21:57 -05:00
J. Nick Koston 84e1e0fb23 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer
# Conflicts:
#	tests/unit_tests/test_writer.py
2026-08-25 13:21:41 -05:00
J. Nick Koston 7f2851f283 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-25 13:20:50 -05:00
J. Nick Koston 57711a0721 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-25 13:20:50 -05:00
J. Nick Koston 1e9499d87d Merge remote-tracking branch 'origin/dev' into esp8266-native-build-surgery 2026-08-25 13:20:50 -05:00
J. Nick Koston 9caeb948f3 Warn when forced-on ccache has no usable binary, skip freshly installed dests in the prefetch, derive the clean-all sandbox from the cache registry 2026-08-25 13:20:30 -05:00
J. Nick Koston aaf76710a9 Merge remote-tracking branch 'origin/esp8266-arduino-toolchain' into esp8266-native-pch 2026-08-25 13:16:51 -05:00
J. Nick Koston 2665a4fa12 [esp8266] Precompile the shared prefix header for src compiles 2026-08-25 13:16:51 -05:00
J. Nick Koston d77be85afa Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 12:49:56 -05:00
J. Nick Koston 41f97a16db Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 12:49:56 -05:00
J. Nick Koston 09da94862f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 12:49:55 -05:00
J. Nick Koston 61f15df4d3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 12:49:55 -05:00
J. Nick Koston 83b5d67e3c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 12:49:55 -05:00
J. Nick Koston eb37f8efbe Fetch registry metadata through the consolidated HTTP path 2026-08-25 12:49:40 -05:00
J. Nick Koston dccd4e91d2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 12:39:03 -05:00
J. Nick Koston d018f5a720 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 12:39:03 -05:00
J. Nick Koston 5aea104907 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 12:39:03 -05:00
J. Nick Koston b6e9845f27 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-25 12:39:02 -05:00
J. Nick Koston e52bfe31f2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 12:39:02 -05:00
J. Nick Koston 64dd23a705 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 12:39:02 -05:00
J. Nick Koston ed369ae353 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-25 12:39:02 -05:00
J. Nick Koston 3426eb2733 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-surgery 2026-08-25 12:38:49 -05:00
J. Nick Koston c91fa2b6fc Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 12:37:47 -05:00
J. Nick Koston e2c2b2f53e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 12:37:47 -05:00
J. Nick Koston 784f3b8680 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 12:37:47 -05:00
J. Nick Koston f8669a34dd Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-25 12:37:46 -05:00
J. Nick Koston 21de71bd7a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 12:37:46 -05:00
J. Nick Koston e47c800805 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 12:37:46 -05:00
J. Nick Koston fce5a94234 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-25 12:37:46 -05:00
J. Nick Koston 94b47496c8 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-surgery 2026-08-25 12:37:36 -05:00
J. Nick Koston 422d1c67da Honor bulk in every per-address decode marker 2026-08-25 11:54:33 -05:00
J. Nick Koston 6c14bff747 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-25 10:47:59 -05:00
J. Nick Koston e5d95bafd0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-25 10:47:59 -05:00
J. Nick Koston 6d9cb2daac Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-25 10:47:58 -05:00
J. Nick Koston 1fa27b79a6 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-25 10:47:58 -05:00
J. Nick Koston 0f41148e5c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-25 10:47:58 -05:00
J. Nick Koston e169f71bae Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-25 10:47:58 -05:00
J. Nick Koston 4e192cf89a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-25 10:47:58 -05:00
J. Nick Koston 515aa96844 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-surgery 2026-08-25 10:47:44 -05:00
J. Nick Koston a0dcb6a5f5 Demote bulk stack-word decode misses to debug, count built components per pattern 2026-08-25 08:37:33 -05:00
J. Nick Koston 2ee448a7a8 Cover the failed-probe fall-through 2026-08-24 19:19:30 -05:00
J. Nick Koston f934f3ac7e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 18:53:58 -05:00
J. Nick Koston 605c894682 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 18:53:58 -05:00
J. Nick Koston fd3654e206 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 18:53:58 -05:00
J. Nick Koston a35290c8bc Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 18:53:57 -05:00
J. Nick Koston d5c0d18c0a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 18:53:57 -05:00
J. Nick Koston b7f3b3f2e1 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 18:53:57 -05:00
J. Nick Koston d217a7e6a8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 18:53:57 -05:00
J. Nick Koston 802a14f90a Hoist the test imports to module level 2026-08-24 18:53:36 -05:00
J. Nick Koston 85c0d86040 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-08-24 18:52:51 -05:00
J. Nick Koston 35d147aef1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/components/esp8266/const.py
2026-08-24 18:52:13 -05:00
J. Nick Koston abefc93225 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 18:51:28 -05:00
J. Nick Koston 9d6ceef241 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 18:51:28 -05:00
J. Nick Koston e87f617a5b Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 18:51:27 -05:00
J. Nick Koston ae8ab5773f Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 18:51:27 -05:00
J. Nick Koston 73a9f420c0 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 18:51:27 -05:00
J. Nick Koston 69a3ab6fb1 Error instead of substituting a state-destroying layout on legacy cores, extract the ld choice, regroup KEY_LDSCRIPT, document segment_length's None 2026-08-24 18:51:10 -05:00
J. Nick Koston 77de13dab3 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 18:48:02 -05:00
J. Nick Koston 8e3aa5e921 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 18:48:02 -05:00
J. Nick Koston d9d2c0bf6b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 18:48:01 -05:00
J. Nick Koston f41aa2ff62 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 18:48:01 -05:00
J. Nick Koston 4b731ce9ce Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 18:48:01 -05:00
J. Nick Koston bcc5a551dc Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 18:48:01 -05:00
J. Nick Koston 50e6a011cb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 18:48:01 -05:00
J. Nick Koston 2cd5db4854 Merge remote-tracking branch 'origin/esp8266-native-build-surgery' into esp8266-native-build-surgery 2026-08-24 18:47:58 -05:00
J. Nick Koston 260bfc2358 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 18:47:07 -05:00
J. Nick Koston 4e66248682 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 18:47:07 -05:00
J. Nick Koston f6c308cefa Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 18:47:07 -05:00
J. Nick Koston 63b25f00cb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 18:47:06 -05:00
J. Nick Koston 44c8ce777a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 18:47:06 -05:00
J. Nick Koston bd9cf790d7 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 18:47:06 -05:00
J. Nick Koston 6eaf22afd8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 18:47:06 -05:00
J. Nick Koston 767b60a914 Merge remote-tracking branch 'origin/dev' into esp8266-native-build-surgery 2026-08-24 18:46:55 -05:00
J. Nick Koston 7ca1b79544 Name the ldscript key, warn when a pre-2.4.2 core cannot honor it, pin the rule
KEY_LDSCRIPT replaces the bare literal at both the table entry and the
lookup, so a typo cannot silently fall back to the layout-moving
default; the regeneration recipe notes that overrides must survive a
refresh; a board pinning an override on an Arduino core <= 2.4.2 warns
that the layout cannot be honored; and board_ld_script gains the test
pinning d1_wroom_02's shipped layout and the size defaults.
2026-08-24 18:46:47 -05:00
J. Nick Koston a25509bda0 Share the per-board ldscript rule via boards.board_ld_script
One source of truth for the PlatformIO pinning and the native
generator's fallback, so the per-board rule cannot drift.
2026-08-24 18:46:47 -05:00
J. Nick Koston 04825d3a58 Reconcile BOARDS with the generated table: d1_wroom_02 joins with its shipped flash layout 2026-08-24 18:46:47 -05:00
J. Nick Koston e714848fb9 Trim comment essays and hoist function-local test imports 2026-08-24 18:46:47 -05:00
J. Nick Koston d7ee824228 Phrase the board-table regen comment imperatively 2026-08-24 18:46:47 -05:00
J. Nick Koston 862b7f7c3e Pin fingerprint stability and sensitivity behaviorally, note the platform pairing 2026-08-24 18:46:47 -05:00
J. Nick Koston 77c41d2579 State what the fingerprint test actually pins 2026-08-24 18:46:47 -05:00
J. Nick Koston 4d92741e69 Pin the decoy anchor, guard unselected segments, fingerprint the module source 2026-08-24 18:46:47 -05:00
J. Nick Koston b2ac49d8a8 Anchor the segment regex, reject unknown segments, and pin real-script fixtures 2026-08-24 18:46:47 -05:00
J. Nick Koston 8fb6496583 Export a surgery fingerprint for linker-script cache stamps 2026-08-24 18:46:47 -05:00
J. Nick Koston 5f3d73720e Patch exactly the named segments and share the segment-line pattern 2026-08-24 18:46:47 -05:00
J. Nick Koston cdd8a16cb9 Add the ESP8266 linker-script surgery and board build metadata 2026-08-24 18:46:47 -05:00
J. Nick Koston a5ae1097cc Restore the fast fail before the baseline build when nothing matched 2026-08-24 18:45:40 -05:00
J. Nick Koston 1739bbf3de Name explicit ninja targets instead of policing mtimes, unify the no-tests accounting per pattern, mark stale-ELF decodes, glob the idedata caches 2026-08-24 18:15:58 -05:00
J. Nick Koston f30802757e Stamp the compile-DB freshness, defer the silent-component failure past the summary, mark every undecoded address, honor all-platform fixtures 2026-08-24 17:06:59 -05:00
J. Nick Koston eb2e9a791b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 16:00:09 -05:00
J. Nick Koston 38bc629db3 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 16:00:09 -05:00
J. Nick Koston ed4c1af5a9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 16:00:09 -05:00
J. Nick Koston 13b9ff5f7f Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 16:00:09 -05:00
J. Nick Koston 7e2c83a397 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 16:00:09 -05:00
J. Nick Koston dafb60434f Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 16:00:08 -05:00
J. Nick Koston 53cb82c76b Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 16:00:08 -05:00
J. Nick Koston 4efc3ecb70 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-24 16:00:08 -05:00
J. Nick Koston 4457158e3b Merge remote-tracking branch 'origin/dev' into esp8266-native-shared-helpers 2026-08-24 15:59:59 -05:00
J. Nick Koston 8d1c58afaa Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 15:58:32 -05:00
J. Nick Koston 37d5ba1807 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 15:58:32 -05:00
J. Nick Koston eaa9e955b2 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 15:58:31 -05:00
J. Nick Koston f6cb25f811 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 15:58:31 -05:00
J. Nick Koston 431312da29 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 15:58:31 -05:00
J. Nick Koston bc86285369 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 15:58:31 -05:00
J. Nick Koston f78c1cb85c Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 15:58:30 -05:00
J. Nick Koston ad437cbd15 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-24 15:58:30 -05:00
J. Nick Koston 7e236bc762 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-24 15:58:30 -05:00
J. Nick Koston 6eed2e5d2b Merge remote-tracking branch 'origin/dev' into esp8266-native-library-converter 2026-08-24 15:58:21 -05:00
J. Nick Koston 4b62689952 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 14:39:01 -05:00
J. Nick Koston 4fb83364e8 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 14:39:01 -05:00
J. Nick Koston 9a4603abce Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 14:39:00 -05:00
J. Nick Koston 66be5a2a6d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 14:39:00 -05:00
J. Nick Koston 3f75a7f7b2 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 14:38:59 -05:00
J. Nick Koston e37275d8ba Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 14:38:59 -05:00
J. Nick Koston 1c440fb30e Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 14:38:59 -05:00
J. Nick Koston 454e380057 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-24 14:38:58 -05:00
J. Nick Koston cd1e5aad67 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-24 14:38:58 -05:00
J. Nick Koston a8c4018536 Merge remote-tracking branch 'origin/dev' into esp8266-native-library-converter 2026-08-24 14:38:49 -05:00
J. Nick Koston 634dfe6f3c Harden the skip path against stale artifacts, tolerate corrupt linker scripts, guard the baseline degrade, mark undecoded addresses 2026-08-24 13:49:50 -05:00
J. Nick Koston 0556c212b2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 13:36:49 -05:00
J. Nick Koston 9b02163b99 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-24 13:36:39 -05:00
J. Nick Koston 3f76981e2d Serialize the cache-stamp command unambiguously, annotate the test helpers 2026-08-24 13:36:07 -05:00
J. Nick Koston 0036732dde Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-24 12:32:55 -05:00
J. Nick Koston 6068d7887f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 12:32:55 -05:00
J. Nick Koston 7dddad5471 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 12:32:55 -05:00
J. Nick Koston 31c6dad695 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 12:32:55 -05:00
J. Nick Koston 49d92b7787 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 12:32:54 -05:00
J. Nick Koston fb8f02e552 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 12:32:54 -05:00
J. Nick Koston 30fff6e91c Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 12:32:54 -05:00
J. Nick Koston 200ee0c9c3 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-24 12:32:54 -05:00
J. Nick Koston 81c375af0b Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-24 12:32:53 -05:00
J. Nick Koston 3ca65ffb0d Cover the file-like backoff tick, settle the batch worker return shape 2026-08-24 12:32:38 -05:00
J. Nick Koston e50057f7bb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-24 12:20:54 -05:00
J. Nick Koston 738f5b1798 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-24 12:20:54 -05:00
J. Nick Koston 81b1a22500 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-24 12:20:54 -05:00
J. Nick Koston 8737ade027 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-24 12:20:42 -05:00
J. Nick Koston c92530b8c0 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-24 12:20:18 -05:00
J. Nick Koston 18890d219e Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-24 12:20:18 -05:00
J. Nick Koston 3425a13d51 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-24 12:20:18 -05:00
J. Nick Koston 68b474fd00 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-24 12:20:18 -05:00
J. Nick Koston efa7fae845 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-24 12:20:18 -05:00
J. Nick Koston 29c290166b Apply simplify pass: flatten the batch worker, drop a dead guard, skip the unread backoff probe 2026-08-24 12:20:14 -05:00
J. Nick Koston d348284d9e Hoist the manifest shape gate into a helper 2026-08-24 12:17:05 -05:00
J. Nick Koston af500d6bec Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 22:25:38 -05:00
J. Nick Koston efb8f5ff1a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 22:25:38 -05:00
J. Nick Koston 0d078a3416 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 22:25:38 -05:00
J. Nick Koston ae2fa92a3d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 22:25:37 -05:00
J. Nick Koston 39b12a9382 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 22:25:37 -05:00
J. Nick Koston bd568038ee Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 22:25:37 -05:00
J. Nick Koston 1aff27727f Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 22:25:37 -05:00
J. Nick Koston 3a248d526d Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 22:25:37 -05:00
J. Nick Koston 2f49405740 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 22:25:36 -05:00
J. Nick Koston d418472a8f Merge remote-tracking branch 'origin/dev' into esp8266-native-library-converter
# Conflicts:
#	esphome/platformio/library.py
#	tests/unit_tests/test_platformio_library.py
2026-08-23 22:25:22 -05:00
J. Nick Koston ac3a6934f6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 22:02:14 -05:00
J. Nick Koston 7db3fd1286 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 22:02:14 -05:00
J. Nick Koston 81cca915f6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 22:02:13 -05:00
J. Nick Koston 5c7a7eee29 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 22:02:13 -05:00
J. Nick Koston abde296f54 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 22:02:13 -05:00
J. Nick Koston 516508ef92 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 22:02:13 -05:00
J. Nick Koston 2a4bd1789c Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 22:02:13 -05:00
J. Nick Koston 7a715ee583 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 22:02:12 -05:00
J. Nick Koston d8dc1dc70e Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 22:02:12 -05:00
J. Nick Koston 5479752da6 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 22:02:12 -05:00
J. Nick Koston b0e4711cc3 Merge remote-tracking branch 'origin/esp8266-native-converter-hardening' into esp8266-native-converter-hardening 2026-08-23 22:01:59 -05:00
J. Nick Koston 1780a54524 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 22:00:36 -05:00
J. Nick Koston 6b5b8e0fd0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 22:00:35 -05:00
J. Nick Koston 568002014e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 22:00:35 -05:00
J. Nick Koston dd5b1a7ae3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 22:00:35 -05:00
J. Nick Koston 0b03327dd9 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 22:00:35 -05:00
J. Nick Koston c0965a3a8a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 22:00:35 -05:00
J. Nick Koston 141fd285c9 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 22:00:34 -05:00
J. Nick Koston d744a98f5b Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 22:00:34 -05:00
J. Nick Koston a03945bbfb Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 22:00:34 -05:00
J. Nick Koston bc2b4bd381 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 22:00:34 -05:00
J. Nick Koston f8acaab6c1 Merge remote-tracking branch 'origin/dev' into esp8266-native-converter-hardening
# Conflicts:
#	script/determine-jobs.py
#	tests/script/test_determine_jobs.py
2026-08-23 22:00:22 -05:00
J. Nick Koston 5f2b8f7251 Type LINK_FLAGS in the gate, skip malformed transitive deps, escape quotes in zephyr CMake entries 2026-08-23 21:59:22 -05:00
J. Nick Koston d80d2c7034 Tolerate malformed repository/description metadata instead of crashing 2026-08-23 21:59:22 -05:00
J. Nick Koston 1f5152892c Give the fake env real membership, widen the manifest gate, route zephyr through the shared lexer 2026-08-23 21:59:22 -05:00
J. Nick Koston 89671f9e0d Normalize captured CPPDEFINES to a CppDefine named tuple at capture time 2026-08-23 21:59:22 -05:00
J. Nick Koston c6f9153e63 Route captured LINKFLAGS to the link line and make Prepend a real front-insert 2026-08-23 21:59:22 -05:00
J. Nick Koston aa3268a6d8 Match SCons' remaining CPPDEFINES spellings, drop dead test scaffolding
A bare 2-tuple is one name=value pair (not -DFOO -D1), a dict maps
names to values, and a None value is a bare define, per processDefines.
The unused caplog_at_info helper and the progress kwarg the download
stubs declared ahead of their PR are gone.
2026-08-23 21:59:22 -05:00
J. Nick Koston 879cbf6264 Cover env access warnings and the unmodelled-subscript degrade 2026-08-23 21:59:22 -05:00
J. Nick Koston 4da8868510 Quote CPPDEFINES, warn on env access, degrade unmodelled subscripts, realify InvalidLibrary
CPPDEFINES joins the quoted buckets (a spaced define no longer splits
across tokens) and its tuple branch validates the pair elements. The
fake env warns on attribute access rather than call, so hasattr/
truthiness branches are diagnosable, with dunder probes excluded; an
unmodelled subscript warns and returns '' instead of a KeyError
discarding the whole capture. Malformed platforms/frameworks values
raise plain InvalidLibrary, giving the non-platform warning branches a
real producer, and their tests use real manifests instead of
monkeypatched raisers. The version-less dependency drop moves to debug:
bundled names (Wire, SPI) made it per-build noise nobody can act on.
2026-08-23 21:59:22 -05:00
J. Nick Koston df76fc6fba Trim comments and docstrings 2026-08-23 21:59:22 -05:00
J. Nick Koston 0d75f597b3 Harden the shared library converter
Split out of #18662: the converter/manifest hardening without the
download parallelization, which stays there.

The PIO extra-script shim moves from espidf/ to platformio/ and gains
type checks for every manifest field, capture of the Append variants and
CPPPATH, warn-once diagnostics for unmodelled env reads, and uniform
shlex quoting so captured values survive the lex_build_flags round-trip.
The dependency walk normalizes every spelling PIO accepts, splits the
routine cross-platform skip (IncompatiblePlatform) from real manifest
problems, validates manifest shape once, and the shared flag lexer
warns and drops trailing or empty glued arguments.
2026-08-23 21:59:22 -05:00
J. Nick Koston 1caad91260 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 21:10:49 -05:00
J. Nick Koston 9ee07ab960 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 21:10:49 -05:00
J. Nick Koston 0155e4c296 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 21:10:48 -05:00
J. Nick Koston db23748616 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 21:10:48 -05:00
J. Nick Koston 1a5c219909 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 21:10:48 -05:00
J. Nick Koston 23a3412752 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 21:10:47 -05:00
J. Nick Koston 148d4f3f3a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 21:10:47 -05:00
J. Nick Koston 936bc708af Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 21:10:46 -05:00
J. Nick Koston 13dcf54a43 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 21:10:46 -05:00
J. Nick Koston 5bccc41ca3 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 21:10:46 -05:00
J. Nick Koston 5ba31dcccb Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 21:10:45 -05:00
J. Nick Koston 3fe4e255d8 Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 21:10:35 -05:00
J. Nick Koston 985a784f5e Point analyze-memory at the platformio escape hatch, test the backend-table invariant instead of asserting at import, fail blank component lists under the flag, clean the arduino idedata cache 2026-08-23 20:53:55 -05:00
J. Nick Koston 0b920477b3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 19:43:43 -05:00
J. Nick Koston bae1291d73 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 19:43:43 -05:00
J. Nick Koston d4715511aa Cover the non-UTF-8 script raise and the note-read race 2026-08-23 19:43:31 -05:00
J. Nick Koston 4a9dfe0456 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 19:38:34 -05:00
J. Nick Koston f973c7bfb7 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 19:38:34 -05:00
J. Nick Koston 0b04623072 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 19:38:33 -05:00
J. Nick Koston a1ea46e002 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 19:38:33 -05:00
J. Nick Koston 7bb4f2ecb2 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 19:38:33 -05:00
J. Nick Koston 1eb0fff084 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 19:38:33 -05:00
J. Nick Koston 2e1217b1e1 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 19:38:32 -05:00
J. Nick Koston 67608f9386 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 19:38:32 -05:00
J. Nick Koston 9c2a3baaa9 Name the platform in the analyze-memory refusal, surface parser-shaped idedata failures, count builds per component under the no-tests flag 2026-08-23 19:38:12 -05:00
J. Nick Koston 983c5a1de9 Decode the linker script strictly, fold the diagnostic note into the cache stamp, fix the comment attachment 2026-08-23 19:35:42 -05:00
J. Nick Koston 5aaf5e8150 Parametrize the build-info staleness test 2026-08-23 19:33:08 -05:00
J. Nick Koston f3851bf3ad Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 19:30:47 -05:00
J. Nick Koston 0bbd09219d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 19:30:47 -05:00
J. Nick Koston d0dc7cc57c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 19:30:47 -05:00
J. Nick Koston b9d40d2b1b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 19:30:47 -05:00
J. Nick Koston 14a68e7b35 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 19:30:47 -05:00
J. Nick Koston c4e8cb5ccd Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 19:30:46 -05:00
J. Nick Koston ecb0c24bee Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 19:30:46 -05:00
J. Nick Koston 5ce8c68df5 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 19:30:46 -05:00
J. Nick Koston 412b7a8b99 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 19:30:46 -05:00
J. Nick Koston e594888176 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter
# Conflicts:
#	esphome/platformio/library.py
2026-08-23 19:30:35 -05:00
J. Nick Koston 6bdd8b1163 Type LINK_FLAGS in the gate, skip malformed transitive deps, escape quotes in zephyr CMake entries 2026-08-23 19:30:02 -05:00
J. Nick Koston 8af64629d7 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:59:47 -05:00
J. Nick Koston 6dbe414b77 Assemble plain .s without the preprocessor, allow unflagging operand-less linker flags 2026-08-23 18:59:45 -05:00
J. Nick Koston 2c489b5e8a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 18:59:00 -05:00
J. Nick Koston e98d3ad066 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 18:59:00 -05:00
J. Nick Koston c89154bb93 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 18:59:00 -05:00
J. Nick Koston fc058a1e14 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 18:59:00 -05:00
J. Nick Koston fa6e6f3d36 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:59:00 -05:00
J. Nick Koston 092aaf9852 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 18:58:59 -05:00
J. Nick Koston 06e3525f82 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 18:58:59 -05:00
J. Nick Koston 476ec16a3d Split the AS and ASPP source kinds to match SCons 2026-08-23 18:58:48 -05:00
J. Nick Koston 6f775ca9af Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:45:16 -05:00
J. Nick Koston 2879861c1c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 18:45:15 -05:00
J. Nick Koston 717a21add7 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 18:45:15 -05:00
J. Nick Koston f27453e570 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 18:45:15 -05:00
J. Nick Koston 2e681bfb2e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:45:15 -05:00
J. Nick Koston 0e9a08a3b5 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 18:45:14 -05:00
J. Nick Koston 7ddbd5c943 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 18:45:14 -05:00
J. Nick Koston d9b3536e9f Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 18:45:14 -05:00
J. Nick Koston 0ed990e311 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 18:45:14 -05:00
J. Nick Koston 69d997521f Guard the bar writes, narrow the cache probe, make a total prefetch failure loud 2026-08-23 18:45:02 -05:00
J. Nick Koston 4c4ccc4444 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:33:24 -05:00
J. Nick Koston 4946221da0 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 18:33:24 -05:00
J. Nick Koston e623bb90ae Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 18:33:24 -05:00
J. Nick Koston 97d9f6be12 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 18:33:24 -05:00
J. Nick Koston 8ef6bd24d6 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:33:24 -05:00
J. Nick Koston 59c3af7533 Complete the toolchain-plumbing merge that the format hook split 2026-08-23 18:33:00 -05:00
J. Nick Koston 344843ec93 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 18:31:08 -05:00
J. Nick Koston 4affd574ac Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 18:31:08 -05:00
J. Nick Koston 4840740032 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers
# Conflicts:
#	esphome/writer.py
2026-08-23 18:31:05 -05:00
J. Nick Koston ae5e5b3011 Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 18:30:06 -05:00
J. Nick Koston 3ab464c345 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 18:30:06 -05:00
J. Nick Koston b74de2dfa2 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 18:30:06 -05:00
J. Nick Koston d4f75e5468 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:26:13 -05:00
J. Nick Koston b458d6b4af Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:26:13 -05:00
J. Nick Koston 9a04c0ffdc ASCII-only shape regexes, document the flash_mode precondition 2026-08-23 18:26:04 -05:00
J. Nick Koston 0e54d7d510 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:20:47 -05:00
J. Nick Koston d8dea887b0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:20:47 -05:00
J. Nick Koston a818f5e259 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 18:20:46 -05:00
J. Nick Koston 1b7db46c8c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 18:20:46 -05:00
J. Nick Koston ea0bab57ff Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 18:20:46 -05:00
J. Nick Koston 71ae4f94ab Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 18:20:46 -05:00
J. Nick Koston 08c7eb627e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 18:20:46 -05:00
J. Nick Koston 7ea8892e0a Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 18:20:45 -05:00
J. Nick Koston dce979245d Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 18:20:45 -05:00
J. Nick Koston 6e65634408 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 18:20:45 -05:00
J. Nick Koston 6300e9b72e Tolerate malformed repository/description metadata instead of crashing 2026-08-23 18:20:43 -05:00
J. Nick Koston 129f50b712 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 18:15:05 -05:00
J. Nick Koston bfafb41888 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 18:15:05 -05:00
J. Nick Koston 093184e950 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 18:15:05 -05:00
J. Nick Koston 51afb0ed25 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 18:15:05 -05:00
J. Nick Koston 7d69b7babd Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 18:15:04 -05:00
J. Nick Koston 6f543c728a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 18:15:04 -05:00
J. Nick Koston 6c63e61261 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 18:15:04 -05:00
J. Nick Koston cb4dd32e19 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 18:15:04 -05:00
J. Nick Koston 6381ed97b9 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 18:15:04 -05:00
J. Nick Koston 786e9ef278 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter
# Conflicts:
#	esphome/platformio/library.py
2026-08-23 18:14:53 -05:00
J. Nick Koston 24ce2195da Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 18:12:27 -05:00
J. Nick Koston d5fe45db66 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 18:12:27 -05:00
J. Nick Koston a027d06231 Give the fake env real membership, widen the manifest gate, route zephyr through the shared lexer 2026-08-23 18:12:14 -05:00
J. Nick Koston b893cee6ca Apply simplify pass: shared idedata warning, platform-keyed backend table, one owner for the cache prefix and trigger files 2026-08-23 18:07:46 -05:00
J. Nick Koston 73fd512a25 Make symbol unflags pair-aware on the link line, drop the dead KEY_FLASH_MODE 2026-08-23 18:03:15 -05:00
J. Nick Koston aaebc6e007 Cover the skipped-size-summary warning in run_compile 2026-08-23 18:00:34 -05:00
J. Nick Koston f0f6671c83 Pin that the native upload path imports no platform component package 2026-08-23 17:52:27 -05:00
J. Nick Koston ebb6ffa509 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:51:16 -05:00
J. Nick Koston e902d8d1fc Widen _collect_sources exclude to Collection 2026-08-23 17:51:09 -05:00
J. Nick Koston f82d8ec99b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:46:54 -05:00
J. Nick Koston a15dbe750f Pin that a non-default flash mode reaches the define and the image header 2026-08-23 17:46:53 -05:00
J. Nick Koston fde0a835b6 Pin board_build.flash_mode unconditionally, dispatch native backends by toolchain, report a skipped size summary 2026-08-23 17:46:23 -05:00
J. Nick Koston 830d12dec7 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 17:27:07 -05:00
J. Nick Koston 08421c9bfb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 17:27:07 -05:00
J. Nick Koston d59f6eb46d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:27:07 -05:00
J. Nick Koston 3c07602fd1 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 17:27:06 -05:00
J. Nick Koston d0811277cc Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 17:27:06 -05:00
J. Nick Koston 32e8c4169c Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 17:27:06 -05:00
J. Nick Koston de126b4879 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 17:27:06 -05:00
J. Nick Koston 8f7534f39a Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 17:27:06 -05:00
J. Nick Koston 6bac1ed950 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 17:27:05 -05:00
J. Nick Koston 57241e40b8 Make failure_reason public now that two modules import it, cover interrupt() on a finished bar 2026-08-23 17:26:47 -05:00
J. Nick Koston 43e053a2a5 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 17:18:01 -05:00
J. Nick Koston 4e97a8f7f5 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 17:18:01 -05:00
J. Nick Koston 26982767bd Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:18:01 -05:00
J. Nick Koston 15d931b17e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 17:18:00 -05:00
J. Nick Koston 8f65599afe Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 17:18:00 -05:00
J. Nick Koston 713fe99024 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 17:18:00 -05:00
J. Nick Koston 68281cfd5c Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 17:18:00 -05:00
J. Nick Koston 76ddbe5ebd Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 17:17:59 -05:00
J. Nick Koston 81d9b943aa Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 17:17:59 -05:00
J. Nick Koston 28f0a7b155 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 17:17:59 -05:00
J. Nick Koston 531bd8ec62 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 17:17:59 -05:00
J. Nick Koston 40e6e406d7 Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 17:17:52 -05:00
J. Nick Koston 6cfbe5b166 Normalize captured CPPDEFINES to a CppDefine named tuple at capture time 2026-08-23 17:15:29 -05:00
J. Nick Koston c97fb7744b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 17:12:40 -05:00
J. Nick Koston b3ad8bd15d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:12:40 -05:00
J. Nick Koston 5990fbbf58 Warn on unrecognized flag shapes reaching the compile line, pin the IPv6 lwIP pair, fix stale comments 2026-08-23 17:12:31 -05:00
J. Nick Koston 6b5b2abdea Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 17:08:17 -05:00
J. Nick Koston ac37167db9 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 17:08:17 -05:00
J. Nick Koston 6da4a07546 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 17:08:17 -05:00
J. Nick Koston 1f44b89815 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 17:08:17 -05:00
J. Nick Koston 3cae91e542 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 17:08:17 -05:00
J. Nick Koston 09e5a7d2ac Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 17:08:16 -05:00
J. Nick Koston 4bb6da7f10 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 17:08:16 -05:00
J. Nick Koston b738b36a39 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 17:08:16 -05:00
J. Nick Koston ac66e3a96c Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 17:08:16 -05:00
J. Nick Koston e7fc3937bf Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 17:08:16 -05:00
J. Nick Koston 70f4555ec8 Route captured LINKFLAGS to the link line and make Prepend a real front-insert 2026-08-23 17:08:04 -05:00
J. Nick Koston c2edfd80eb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:54:58 -05:00
J. Nick Koston e2aee2b28e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:54:58 -05:00
J. Nick Koston 726f0b5b57 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:54:57 -05:00
J. Nick Koston b3da79f65d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:54:57 -05:00
J. Nick Koston 75891a3449 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:54:57 -05:00
J. Nick Koston 5c62bd7abf Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:54:57 -05:00
J. Nick Koston 905c0835f4 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:54:57 -05:00
J. Nick Koston 5f20ddb630 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:54:56 -05:00
J. Nick Koston 6cfb915aeb Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:54:56 -05:00
J. Nick Koston 04a44d6e63 Let ProgressBar own the mid-row interrupt, share the part-file naming, fold duplicate except arms 2026-08-23 16:54:33 -05:00
J. Nick Koston cb10904fa3 Keep the combined bar steady during a backoff sleep 2026-08-23 16:49:54 -05:00
J. Nick Koston f1b2258661 Stop the false build_src_flags warning, share the idedata error tuple, make the no-tests guard per platform 2026-08-23 16:48:36 -05:00
J. Nick Koston 3f10a8ca36 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-08-23 16:43:20 -05:00
J. Nick Koston ad4c59873b Read flash mode from its real producer, share the mode set, store the scanf decision
flash_mode comes from the board_build.flash_mode option the component
already pins (validated by cv.one_of against the same BUILD_FLASH_MODES,
now living in const.py so the two sides cannot drift), retiring
KEY_FLASH_MODE from the generator. The scanf-float decision is stored in
CORE.data where it is computed instead of being a discarded local, so
KEY_SCANF_FLOAT has a producer in this PR. A trailing bare -include in
build_src_flags fails by name instead of degrading into the source dir.
2026-08-23 16:42:25 -05:00
J. Nick Koston 09d714bbef Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:36:12 -05:00
J. Nick Koston 436f06eb6d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:36:10 -05:00
J. Nick Koston 9f1dd87938 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:36:08 -05:00
J. Nick Koston 03b994e23e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:36:06 -05:00
J. Nick Koston 9b3aaa4ef0 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:36:04 -05:00
J. Nick Koston 5883e5505f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:36:02 -05:00
J. Nick Koston 9ab69059bd Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:36:00 -05:00
J. Nick Koston 89e5ba00de Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:35:58 -05:00
J. Nick Koston 81b1678498 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:35:56 -05:00
J. Nick Koston ba0d9e77db Never log a blank prefetch reason, keep the download error over a tick failure
Both prefetch warning loops format through _failure_reason so a
message-less exception cannot log blank. A bar-frame write failure in
the failure path cannot displace the download error, the failure list
is annotated BaseException (cancellations are entries too), the Ctrl-C
docstring notes an in-progress extraction runs to completion, and the
wave-prefetch docstring carries the superseded-sibling caveat.
2026-08-23 16:35:48 -05:00
J. Nick Koston 6f0dffeb37 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:31:26 -05:00
J. Nick Koston 74003888a1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:31:24 -05:00
J. Nick Koston e468431081 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:31:22 -05:00
J. Nick Koston 9134ba29d2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:31:20 -05:00
J. Nick Koston e460ead96b Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:31:18 -05:00
J. Nick Koston 0b19867efb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:31:16 -05:00
J. Nick Koston 212a02a819 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:31:14 -05:00
J. Nick Koston 330f070921 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:31:12 -05:00
J. Nick Koston f6ae5e4892 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:31:10 -05:00
J. Nick Koston b0b174f3e2 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:31:08 -05:00
J. Nick Koston d8857080f0 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:31:06 -05:00
J. Nick Koston c285af3857 Cover the Flash line through the shared bar 2026-08-23 16:31:03 -05:00
J. Nick Koston 6b39cbb3e0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:25:37 -05:00
J. Nick Koston 8ac04d41e4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:25:35 -05:00
J. Nick Koston b7e0952eb5 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:25:33 -05:00
J. Nick Koston 5f0d2ff217 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:25:30 -05:00
J. Nick Koston 28b400f942 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:25:28 -05:00
J. Nick Koston 3280248778 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:25:26 -05:00
J. Nick Koston 81ffa42c66 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:25:24 -05:00
J. Nick Koston d7d236c6bc Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:25:22 -05:00
J. Nick Koston de00530c0e Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:25:20 -05:00
J. Nick Koston acf5ce718c Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:25:18 -05:00
J. Nick Koston 5904928f0c Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:25:16 -05:00
J. Nick Koston dceeee69d3 Restore the size summary to its dev shape
The defensive spiral (#18668, closed) guarded inputs that cannot occur:
gen_esp32part validates partitions.csv before a build can succeed, and
esp_idf_size.json's realistic failures do not produce the handled
shapes. This PR's real change stands alone again: the bar moves to
build_helpers as print_size_line, with dev behavior everywhere else.
2026-08-23 16:25:11 -05:00
J. Nick Koston f1d270198c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:18:01 -05:00
J. Nick Koston a95f992430 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:17:59 -05:00
J. Nick Koston a8af46341a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:17:57 -05:00
J. Nick Koston 2b617cd691 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:17:55 -05:00
J. Nick Koston 983c63f7e5 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:17:53 -05:00
J. Nick Koston af2d71e673 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:17:51 -05:00
J. Nick Koston 9fd0b47b39 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:17:49 -05:00
J. Nick Koston 03c7d3b343 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:17:47 -05:00
J. Nick Koston d405db1268 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:17:45 -05:00
J. Nick Koston 8cac10d319 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:17:43 -05:00
J. Nick Koston 030a3b7ab3 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:17:41 -05:00
J. Nick Koston dfc26e9f09 Mirror the named-file arm and tightened checks 2026-08-23 16:17:37 -05:00
J. Nick Koston 008555d600 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:12:15 -05:00
J. Nick Koston 1ec7e7b285 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:12:13 -05:00
J. Nick Koston 997024a4e3 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:12:11 -05:00
J. Nick Koston 076db937e1 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:12:09 -05:00
J. Nick Koston e27bbd25e7 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:12:07 -05:00
J. Nick Koston e369a9a647 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:12:05 -05:00
J. Nick Koston 034a872e21 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:12:03 -05:00
J. Nick Koston 4f9941decb Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:12:01 -05:00
J. Nick Koston 385681121f Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:11:59 -05:00
J. Nick Koston c395861fa3 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:11:57 -05:00
J. Nick Koston 30b2bbfe3a Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:11:55 -05:00
J. Nick Koston 3af17d5c92 Mirror the named missing-table raise 2026-08-23 16:11:52 -05:00
J. Nick Koston ccf7da5414 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:10:02 -05:00
J. Nick Koston 869bc2c99a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:10:00 -05:00
J. Nick Koston b05a2c6592 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:09:58 -05:00
J. Nick Koston 412959f11a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:09:56 -05:00
J. Nick Koston 78d294ed86 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:09:54 -05:00
J. Nick Koston c04eb4128f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:09:52 -05:00
J. Nick Koston 934e53298a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:09:50 -05:00
J. Nick Koston 72d6864938 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:09:48 -05:00
J. Nick Koston 89ffacaffb Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:09:46 -05:00
J. Nick Koston 6eff668dba Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:09:44 -05:00
J. Nick Koston 350202efa6 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:09:42 -05:00
J. Nick Koston 14388c859a Mirror the backstop-ownership trim from the standalone 2026-08-23 16:09:26 -05:00
J. Nick Koston 78468d7172 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 16:07:02 -05:00
J. Nick Koston fc8953d9cc Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 16:07:00 -05:00
J. Nick Koston f102abef57 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 16:06:58 -05:00
J. Nick Koston 57c63ee3fd Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 16:06:56 -05:00
J. Nick Koston 6284a701d8 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 16:06:54 -05:00
J. Nick Koston 5d352d090b Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 16:06:52 -05:00
J. Nick Koston 36c652473a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 16:06:50 -05:00
J. Nick Koston 7061bd7e70 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 16:06:48 -05:00
J. Nick Koston fe274653bd Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 16:06:46 -05:00
J. Nick Koston 7beb0078c2 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 16:06:44 -05:00
J. Nick Koston e26dbb6d75 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 16:06:42 -05:00
J. Nick Koston 7aa0f30ceb Mirror the unreachable-arm removal from the standalone 2026-08-23 16:06:38 -05:00
J. Nick Koston 38c5e4f997 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:59:15 -05:00
J. Nick Koston 612545b9a8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:59:13 -05:00
J. Nick Koston b24481cda6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:59:11 -05:00
J. Nick Koston 9c3c2823c9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:59:09 -05:00
J. Nick Koston dd52c519de Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:59:08 -05:00
J. Nick Koston 691be52c88 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:59:06 -05:00
J. Nick Koston cfbaef1d8d Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:59:03 -05:00
J. Nick Koston 438a4ddc14 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 15:59:01 -05:00
J. Nick Koston 5a749c4b5d Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 15:58:59 -05:00
J. Nick Koston 3de58dae99 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 15:58:57 -05:00
J. Nick Koston fd2971bd70 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 15:58:55 -05:00
J. Nick Koston 8a9bb7741a Mirror the truncated-size-report classification 2026-08-23 15:58:52 -05:00
J. Nick Koston 1b28c3eadb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:52:45 -05:00
J. Nick Koston ee431eb723 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:52:43 -05:00
J. Nick Koston 219532ce01 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:52:41 -05:00
J. Nick Koston 8b76e62be1 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:52:39 -05:00
J. Nick Koston 6dbd89054b Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:52:37 -05:00
J. Nick Koston f93fa22de8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:52:35 -05:00
J. Nick Koston fd15a22c94 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:52:33 -05:00
J. Nick Koston 393dabadf8 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 15:52:30 -05:00
J. Nick Koston 56dc9124ab Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 15:52:28 -05:00
J. Nick Koston 92b655c5a0 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 15:52:26 -05:00
J. Nick Koston c474421399 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 15:52:24 -05:00
J. Nick Koston ca611a3159 Mirror the size-summary visibility refinements from the standalone
Corrupt shapes at any level warn as malformed while a simply-absent
DRAM/DIRAM region stays at debug, the backstop warning carries its
traceback, and the image_size warning names its file.
2026-08-23 15:51:30 -05:00
J. Nick Koston 1cdaddad4f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:46:01 -05:00
J. Nick Koston a8e71f125a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:45:59 -05:00
J. Nick Koston cb62f892c7 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:45:56 -05:00
J. Nick Koston 2283fafc9b Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:45:54 -05:00
J. Nick Koston 115ef50090 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:45:52 -05:00
J. Nick Koston 48d353926e Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:45:50 -05:00
J. Nick Koston abb0f9e56a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:45:48 -05:00
J. Nick Koston 6dbef0d0bb Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 15:45:46 -05:00
J. Nick Koston 832c6feecc Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 15:45:44 -05:00
J. Nick Koston 41b0fe6747 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 15:45:42 -05:00
J. Nick Koston e580e267ce Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 15:45:40 -05:00
J. Nick Koston d3590ffd7c Port the standalone size-summary hardening into the chain copy
The full #18668 state, adapted to the shared bar: _ram_bar/_flash_bar
return validated (used, total) pairs printed through print_size_line,
the partition parser returns None for legitimate absence and raises
only for a broken table, skips follow the warn/debug visibility rule,
and run_compile passes the table path unconditionally. Ported now so
the merge-time conflict resolves itself; the chain-only exact-format
and RAM-vs-Flash isolation tests stay.
2026-08-23 15:45:36 -05:00
J. Nick Koston de4e395715 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:33:44 -05:00
J. Nick Koston f955c59fe4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:33:42 -05:00
J. Nick Koston 9cbdfa07cb Require bodies on the MMU segment sizes, split driver link flags, warn on a stuck note
A bare -DMMU_IRAM_SIZE would preprocess to len = 1 and fail far away in
ld (or as a misleading testing-mode message), so MMU_CUSTOM requires a
body on both segment sizes before the shape check. -fuse-ld=/-specs=/
--specs= are driver options with no -Wl, spelling, so they get their
own rejection instead of advice that would make things worse. An
unremovable stale stderr note now warns with the clean hint, since its
consequence is a permanently unstamped cache.
2026-08-23 15:33:37 -05:00
J. Nick Koston 5c9d73c1e2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:27:53 -05:00
J. Nick Koston eea31bf571 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:27:51 -05:00
J. Nick Koston db2ea1b935 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:27:49 -05:00
J. Nick Koston f7a3e4fabf Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:27:47 -05:00
J. Nick Koston fc9037b2b5 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:27:44 -05:00
J. Nick Koston ebc6f83053 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:27:42 -05:00
J. Nick Koston 8c96e50b46 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:27:40 -05:00
J. Nick Koston 54429bcdfb Name the ldscript key, warn when a pre-2.4.2 core cannot honor it, pin the rule
KEY_LDSCRIPT replaces the bare literal at both the table entry and the
lookup, so a typo cannot silently fall back to the layout-moving
default; the regeneration recipe notes that overrides must survive a
refresh; a board pinning an override on an Arduino core <= 2.4.2 warns
that the layout cannot be honored; and board_ld_script gains the test
pinning d1_wroom_02's shipped layout and the size defaults.
2026-08-23 15:27:36 -05:00
J. Nick Koston 8018a0d930 Cover the bar-less logging guard and the uncancelled backoff slice 2026-08-23 15:25:29 -05:00
J. Nick Koston 63d061bc1d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:09:19 -05:00
J. Nick Koston 65793b0eb7 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:09:18 -05:00
J. Nick Koston 317b81b3ff Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:09:15 -05:00
J. Nick Koston a3c93fb8ea Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:09:13 -05:00
J. Nick Koston 720f113f25 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:09:11 -05:00
J. Nick Koston 9b403279cb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:09:09 -05:00
J. Nick Koston 17ba07d6fe Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:09:07 -05:00
J. Nick Koston 20920e0971 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 15:09:05 -05:00
J. Nick Koston 81be569a85 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 15:09:03 -05:00
J. Nick Koston 641c80b193 Use the caplog fixture where the deleted helper was 2026-08-23 15:09:00 -05:00
J. Nick Koston 21a3509634 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 15:06:58 -05:00
J. Nick Koston 91f0554a2c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 15:06:56 -05:00
J. Nick Koston 67bf5f9a21 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 15:06:54 -05:00
J. Nick Koston c46860bf57 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 15:06:52 -05:00
J. Nick Koston 66d0358d03 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 15:06:50 -05:00
J. Nick Koston 7c8f352ab1 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 15:06:48 -05:00
J. Nick Koston e563ad3724 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 15:06:46 -05:00
J. Nick Koston 8170cd3d96 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 15:06:44 -05:00
J. Nick Koston e2eae002e6 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 15:06:42 -05:00
J. Nick Koston 065867f815 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 15:06:40 -05:00
J. Nick Koston 5aebd7cb41 Match SCons' remaining CPPDEFINES spellings, drop dead test scaffolding
A bare 2-tuple is one name=value pair (not -DFOO -D1), a dict maps
names to values, and a None value is a bare define, per processDefines.
The unused caplog_at_info helper and the progress kwarg the download
stubs declared ahead of their PR are gone.
2026-08-23 15:05:43 -05:00
J. Nick Koston d0e27bd174 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 14:42:33 -05:00
J. Nick Koston 5d4a18f9e5 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 14:42:31 -05:00
J. Nick Koston c12e652acf Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 14:42:29 -05:00
J. Nick Koston 94dc7eccc3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 14:42:27 -05:00
J. Nick Koston 96f8c021bd Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 14:42:25 -05:00
J. Nick Koston 8a8ae69639 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 14:42:23 -05:00
J. Nick Koston fb14f2f052 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 14:42:21 -05:00
J. Nick Koston 6497ca1496 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 14:42:19 -05:00
J. Nick Koston 759ddfc91d Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 14:42:17 -05:00
J. Nick Koston 062c542c36 Give worker log records their own line, harden the cancellation sentinel
A logging filter installed for the batch's duration ends a partial bar
row (under the bar's lock) before any record is emitted, so a mirror
retry warning from a worker is no longer overwritten by the next CR
frame. The Ctrl-C sentinel derives from BaseException so a broad
except Exception in the download layers cannot convert an abort into a
retry, an abandoned job is reported like a failure instead of reading
as a completed download, and the mirror-sweep backoff sleeps through
the cancellation tick so a Ctrl-C during a retry window aborts at the
boundary instead of after it. The docstring states the parked-socket
worst case.
2026-08-23 14:42:00 -05:00
J. Nick Koston f0ed1ac8ba Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 14:31:41 -05:00
J. Nick Koston 718157d37f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 14:31:39 -05:00
J. Nick Koston a5c7757c4f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 14:31:36 -05:00
J. Nick Koston f54f0bf60f Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 14:31:34 -05:00
J. Nick Koston f4321dbf17 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 14:31:32 -05:00
J. Nick Koston 46f36409ce Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 14:31:30 -05:00
J. Nick Koston b18e7997f1 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 14:31:28 -05:00
J. Nick Koston d23e9a205a Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 14:31:26 -05:00
J. Nick Koston 03a443c2b7 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 14:31:24 -05:00
J. Nick Koston 0c97e2b354 Route single-archive waves through the batch runner
A dependency chain (api -> noise-c -> libsodium) discovers one archive
per wave, so the <2 gate sent every chained download through the legacy
per-file path. Sized registry archives now always use the batch runner:
one download method, one bar; the per-file path remains only for
unknown-size, git, and local sources.
2026-08-23 14:31:18 -05:00
J. Nick Koston 6ae81d49b9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 14:17:42 -05:00
J. Nick Koston 5166e1b207 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 14:17:40 -05:00
J. Nick Koston b6695239eb Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 14:17:38 -05:00
J. Nick Koston 24681da5e0 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 14:17:35 -05:00
J. Nick Koston cf3eac109c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 14:17:33 -05:00
J. Nick Koston 55323596a9 Resolve registry metadata once, canonicalize the ccache knob, disable on an empty value
registry_download memoizes per process (failures uncached), so the
prefetch and the install share one metadata round-trip per package.
The idf ccache env always hands idf.py exactly one canonical spelling:
the no-ccache path exports 0 so an unparsable inherited value or a
probe-rejected shim cannot enable it, the enabled path exports 1
whatever accepted spelling arrived, and forced-on still runs the
resolver for its no-binary warning. An empty env value keeps its
historical disable meaning instead of falling to the default policy.
2026-08-23 14:17:29 -05:00
J. Nick Koston a429721472 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 14:06:14 -05:00
J. Nick Koston a80b5a9dd0 Cover the flash-mode rejection and src-flag pass-through 2026-08-23 14:06:11 -05:00
J. Nick Koston b0b52bec81 Ungate the build_src_flags producer for the native generator
The generator now reads build_src_flags instead of hardcoding the
throw_stubs force-include, so the option must be set on both toolchains;
gated, the native build silently lost the include (+168 bytes of
libstdc++ throw strings). Verified byte-identical again.
2026-08-23 14:01:34 -05:00
J. Nick Koston 9e623309b4 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:57:24 -05:00
J. Nick Koston 1ccd3cdee8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:57:22 -05:00
J. Nick Koston 14d8e5dbfe Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:57:20 -05:00
J. Nick Koston 3bb8b667fe Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:57:19 -05:00
J. Nick Koston ea270ae2a1 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:57:17 -05:00
J. Nick Koston 87a01b7ed9 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:57:15 -05:00
J. Nick Koston f8957a94f1 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:57:13 -05:00
J. Nick Koston 4803a92554 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 13:57:11 -05:00
J. Nick Koston 3a35c75ec1 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 13:57:09 -05:00
J. Nick Koston 8536d54998 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 13:57:07 -05:00
J. Nick Koston 10bccf3fc0 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-converter-hardening 2026-08-23 13:57:05 -05:00
J. Nick Koston b070d1631c Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 13:57:03 -05:00
J. Nick Koston 350a2a84cc Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-08-23 13:56:47 -05:00
J. Nick Koston 4cc3012d98 Read build_src_flags from its producer, share the ldscript rule, shape-check flash_mode
The throw_stubs force-include now comes from the build_src_flags option
esp8266/__init__ pins, collapsing the two spellings to one source of
truth; -include paths resolve against the source root. The ldscript
fallback consumes boards.board_ld_script instead of duplicating the
per-board rule, flash_mode is checked against its closed set before
landing unquoted in the elf2bin command, and the board-gate comment no
longer names a nonexistent validator.
2026-08-23 13:56:27 -05:00
J. Nick Koston 39f6425170 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:54:27 -05:00
J. Nick Koston 7cf3ed848e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:54:26 -05:00
J. Nick Koston ad7d8eeeea Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:54:26 -05:00
J. Nick Koston 5e54e2e9ba Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:54:26 -05:00
J. Nick Koston 14a9a903c8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:54:26 -05:00
J. Nick Koston fba56787e7 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:54:26 -05:00
J. Nick Koston abcfaa1810 Share the per-board ldscript rule via boards.board_ld_script
One source of truth for the PlatformIO pinning and the native
generator's fallback, so the per-board rule cannot drift.
2026-08-23 13:54:22 -05:00
J. Nick Koston 6b5b13c17e Pin the LOW_MEMORY lwIP fall-through, veto the stamp on a stuck stale note
LOW_MEMORY is upstream's else branch, so the default variant stands in
for it and every listed knob wins -- pinned for the ordinary SNTP
multi-server config where esp8266's HIGHER_BANDWIDTH_LOW_FLASH must
prevail. A stale warn note that cannot be removed now vetoes the stamp
(mirror of the lost-note case), and the unreadable-cached-note warning
names its cause.
2026-08-23 13:51:54 -05:00
J. Nick Koston c822b80c95 Cover env access warnings and the unmodelled-subscript degrade 2026-08-23 13:49:03 -05:00
J. Nick Koston 51384f9743 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:37:27 -05:00
J. Nick Koston 4e37acdc01 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:37:24 -05:00
J. Nick Koston 9766f6e911 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:37:22 -05:00
J. Nick Koston 463a86be3c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
#	tests/unit_tests/test_platformio_library.py
2026-08-23 13:37:08 -05:00
J. Nick Koston 8011be1f61 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:36:14 -05:00
J. Nick Koston 713550ad7b Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:36:12 -05:00
J. Nick Koston 74a4bffb3d Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:36:10 -05:00
J. Nick Koston ae8aa3fee9 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 13:36:08 -05:00
J. Nick Koston ce0a0da42a Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 13:36:06 -05:00
J. Nick Koston 2199fcc851 Restore the malformed-manifest raises lost in the merge resolution 2026-08-23 13:35:52 -05:00
J. Nick Koston 84dc92f5ae Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:35:15 -05:00
J. Nick Koston ba58435d5f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:35:13 -05:00
J. Nick Koston 9233f0f2f1 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:35:11 -05:00
J. Nick Koston 554e19ccdb Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 13:35:09 -05:00
J. Nick Koston 9662fea8b9 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 13:35:07 -05:00
J. Nick Koston b4031dc53a Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter
# Conflicts:
#	esphome/platformio/library.py
2026-08-23 13:35:04 -05:00
J. Nick Koston eb958bd0a0 Quote CPPDEFINES, warn on env access, degrade unmodelled subscripts, realify InvalidLibrary
CPPDEFINES joins the quoted buckets (a spaced define no longer splits
across tokens) and its tuple branch validates the pair elements. The
fake env warns on attribute access rather than call, so hasattr/
truthiness branches are diagnosable, with dunder probes excluded; an
unmodelled subscript warns and returns '' instead of a KeyError
discarding the whole capture. Malformed platforms/frameworks values
raise plain InvalidLibrary, giving the non-platform warning branches a
real producer, and their tests use real manifests instead of
monkeypatched raisers. The version-less dependency drop moves to debug:
bundled names (Wire, SPI) made it per-build noise nobody can act on.
2026-08-23 13:34:19 -05:00
J. Nick Koston 79fae3b709 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:19:31 -05:00
J. Nick Koston 93b0bdff2b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:19:29 -05:00
J. Nick Koston 38c9eb7568 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:19:27 -05:00
J. Nick Koston 87ed752797 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:19:25 -05:00
J. Nick Koston 55b3eb4e0d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:19:23 -05:00
J. Nick Koston f2eeebc3a1 Type the prefetch tracker 2026-08-23 13:19:19 -05:00
J. Nick Koston b2d0af3316 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:18:31 -05:00
J. Nick Koston 5aa61235e4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:18:29 -05:00
J. Nick Koston b97ee5f939 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:18:27 -05:00
J. Nick Koston 68deff0851 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:18:25 -05:00
J. Nick Koston 0557d7c816 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:18:23 -05:00
J. Nick Koston b797c582ef Name the pending-archive tuple 2026-08-23 13:18:19 -05:00
J. Nick Koston c92b734bb9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:17:28 -05:00
J. Nick Koston b805d73c07 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:17:26 -05:00
J. Nick Koston f03c8265ec Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:17:24 -05:00
J. Nick Koston 9013a6e6ad Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:17:22 -05:00
J. Nick Koston 4c8fdbb65b Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:17:20 -05:00
J. Nick Koston 7eb6de0c32 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:17:18 -05:00
J. Nick Koston f0be047453 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:17:16 -05:00
J. Nick Koston 2da0319eaa Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 13:17:14 -05:00
J. Nick Koston c376d32db4 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 13:17:12 -05:00
J. Nick Koston 59fc108aa7 Cover the prefetch blanket guard 2026-08-23 13:17:08 -05:00
J. Nick Koston 7af97902d2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:12:53 -05:00
J. Nick Koston 34456bc283 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:12:53 -05:00
J. Nick Koston f5ae74a25b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:12:53 -05:00
J. Nick Koston b582fa2257 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 13:12:53 -05:00
J. Nick Koston bc44803b5b Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:12:53 -05:00
J. Nick Koston 81e1774b18 Adapt the package prefetch to the folded batch-download API 2026-08-23 13:12:41 -05:00
J. Nick Koston 36c5e39371 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 13:10:39 -05:00
J. Nick Koston fd61eda4a2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 13:10:39 -05:00
J. Nick Koston 8d45edbb3e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 13:10:39 -05:00
J. Nick Koston 2d44dacbed Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-23 13:10:36 -05:00
J. Nick Koston dc00335707 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 13:09:54 -05:00
J. Nick Koston 485725d734 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 13:09:54 -05:00
J. Nick Koston 0b598d18dc Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 13:09:53 -05:00
J. Nick Koston a272ca9e17 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 13:09:53 -05:00
J. Nick Koston e40537cc34 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 13:09:53 -05:00
J. Nick Koston 9d761102e5 Size the prefetch from the registry, fold the batch API, guard the prefetch
The registry response already carries each package file's size, so the
combined bar is sized from URLSource instead of a HEAD sweep; the probe,
its all-or-nothing fallback, and its duplicate Content-Length parsing are
gone, and archives without a reported size simply stay on the sequential
path. run_batch_downloads now takes (name, size, fetch) jobs and builds
the (now private) progress bar itself, collecting failures from future
results instead of a shared list; both call sites use functools.partial
instead of lambda factories. The prefetch touches only URLSource, so the
progress parameter comes off Source/Git/Local/ConvertedLibrary, and the
wave prefetch is wrapped best-effort like its ESP-IDF twin, which also
dedupes by dest only after the verifiability check. ProgressBar.done()
itself now skips the newline when no frame was drawn or the 100% frame
already ended the line, collapsing the batch wrapper's guard and fixing
the stray blank line after OTA uploads.
2026-08-23 13:08:32 -05:00
J. Nick Koston 1372ec8ad2 Trim the shape-key comment 2026-08-23 13:07:33 -05:00
J. Nick Koston c4ddad0237 Trim comments and docstrings 2026-08-23 12:57:59 -05:00
J. Nick Koston 6d4d9aa1ce Trim comments and docstrings 2026-08-23 12:57:17 -05:00
J. Nick Koston caff71c17a Trim comments and docstrings 2026-08-23 12:56:31 -05:00
J. Nick Koston 8e4c9c31e6 Merge branch 'esp8266-native-converter-hardening' into esp8266-native-library-converter 2026-08-23 12:55:57 -05:00
J. Nick Koston a478ae4a46 Trim comments and docstrings 2026-08-23 12:55:52 -05:00
J. Nick Koston 9c9ddea00c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 12:34:10 -05:00
J. Nick Koston 33c010e1b0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 12:34:08 -05:00
J. Nick Koston 7155d5446b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 12:34:06 -05:00
J. Nick Koston 590605c417 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 12:34:03 -05:00
J. Nick Koston dcd76ec9de Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 12:34:01 -05:00
J. Nick Koston 36ea8a2c17 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 12:33:59 -05:00
J. Nick Koston 7c7deba4e4 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 12:33:57 -05:00
J. Nick Koston bd69eab7fb Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 12:33:55 -05:00
J. Nick Koston 5adaee5408 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 12:33:53 -05:00
J. Nick Koston b903c884fd Absorb the converter-hardening split (#18685); this PR keeps only the download parallelization 2026-08-23 12:33:21 -05:00
J. Nick Koston 9731c9527a Harden the shared library converter
Split out of #18662: the converter/manifest hardening without the
download parallelization, which stays there.

The PIO extra-script shim moves from espidf/ to platformio/ and gains
type checks for every manifest field, capture of the Append variants and
CPPPATH, warn-once diagnostics for unmodelled env reads, and uniform
shlex quoting so captured values survive the lex_build_flags round-trip.
The dependency walk normalizes every spelling PIO accepts, splits the
routine cross-platform skip (IncompatiblePlatform) from real manifest
problems, validates manifest shape once, and the shared flag lexer
warns and drops trailing or empty glued arguments.
2026-08-23 12:32:44 -05:00
J. Nick Koston 8d0eab9111 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 12:19:24 -05:00
J. Nick Koston 9f6d66a2e7 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-23 12:18:51 -05:00
J. Nick Koston eb982e07a7 Veto the ld-script cache stamp when the warn note is lost, widen the linker denylist
A failed stderr-sidecar write no longer stamps the cache: the next build
re-runs -E and re-derives the preprocessor diagnostic honestly instead
of losing it for the life of the build dir. The sidecar unlink joins the
best-effort contract. The plain-linker denylist gains the
-nodefaultlibs/-nostdlib/-rdynamic family and the -fuse-ld=/--specs=
prefixes, with a comment naming it best-effort rather than complete.
The damaged-file helper test now lives only in test_helpers.py beside
the OSError-branch coverage.
2026-08-23 12:17:43 -05:00
J. Nick Koston 10d82b129a Rely on the lex funnel's empty-argument drop
The funnel now warns and drops empty glued arguments itself, so the
raise here had nothing left to catch.
2026-08-23 12:15:52 -05:00
J. Nick Koston 49bdd061b8 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 12:15:20 -05:00
J. Nick Koston 88cc355293 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 12:15:19 -05:00
J. Nick Koston 25b429de5d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 12:15:19 -05:00
J. Nick Koston 65f116eaf8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 12:15:19 -05:00
J. Nick Koston 9bb4fedc98 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 12:15:19 -05:00
J. Nick Koston f595a32434 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 12:15:19 -05:00
J. Nick Koston 1959913347 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 12:15:18 -05:00
J. Nick Koston 035555b24c Drop an empty glued flag argument at the lex funnel
shlex.split('-D ""') left a bare -D that gcc resolves by eating the
next flag; the funnel now warns and drops it for every consumer, which
also retires raise_on_empty_arg_flags, whose staged ESP8266 caller no
longer has anything to catch.
2026-08-23 12:15:04 -05:00
J. Nick Koston 1b255b429f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 12:05:21 -05:00
J. Nick Koston 15727692e0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 12:05:19 -05:00
J. Nick Koston 244e275dfb Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 12:05:17 -05:00
J. Nick Koston d53356a2b0 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 12:05:15 -05:00
J. Nick Koston 92ab6b7581 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 12:05:13 -05:00
J. Nick Koston 187df36971 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 12:05:11 -05:00
J. Nick Koston 353ce8a3a2 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 12:05:09 -05:00
J. Nick Koston f8de6fe0d1 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 12:05:07 -05:00
J. Nick Koston 5137c3f16b Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 12:05:05 -05:00
J. Nick Koston ea3ff0e372 Abort in-flight batch downloads on Ctrl-C, make the deferral test hermetic
cancel_futures only drops queued jobs, and the non-daemon workers are
joined at interpreter exit, so a Ctrl-C during the ESP-IDF toolchain
fetch waited out every in-flight archive. The tracker each job reports
through now checks a cancellation flag set when the wait raises, so
downloads abort at their next progress tick and the resumable .part
files keep the bytes already fetched.

The wave-deferral test stubs _content_lengths instead of issuing real
HEAD requests that passed only by failing, the dead hasattr branch in
the HEAD-probe test is gone, and the .C suffix comment names the SCons
divergence instead of claiming parity.
2026-08-23 12:04:49 -05:00
J. Nick Koston cf7c6151e7 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 11:37:10 -05:00
J. Nick Koston 23c1527cf0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 11:37:08 -05:00
J. Nick Koston bcc1004b5d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 11:37:06 -05:00
J. Nick Koston 3ea83b12f5 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 11:37:04 -05:00
J. Nick Koston 6b35e082bf Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 11:37:02 -05:00
J. Nick Koston 8a10914d8d Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 11:37:00 -05:00
J. Nick Koston af195eb1fc Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 11:36:58 -05:00
J. Nick Koston 1157189b36 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 11:36:56 -05:00
J. Nick Koston dd7a25b302 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 11:36:54 -05:00
J. Nick Koston 7c0e03f309 Capture the Append variants, warn on unmodelled env reads, quote every lexed bucket
Prepend/AppendUnique/PrependUnique write the same captured keys and now
alias Append instead of no-op'ing away a link directory. env.get on an
unmodelled var warns once so a script taking the default branch is
diagnosable. LIBS/LINKFLAGS/CPPFLAGS entries are shlex-quoted like the
path buckets, since each is one argv token in SCons and re-lexing must
not split a spaced value. The HEAD probes follow the happy-eyeballs
convention, and the tool-prefetch backstop keeps its traceback at debug.
2026-08-23 11:36:36 -05:00
J. Nick Koston 412bc4be7f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 10:48:54 -05:00
J. Nick Koston acc919e993 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 10:48:54 -05:00
J. Nick Koston 610d630cd4 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 10:48:54 -05:00
J. Nick Koston 34e2a82d8d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 10:48:54 -05:00
J. Nick Koston 13eed46d28 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 10:48:54 -05:00
J. Nick Koston e660c126f8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 10:48:53 -05:00
J. Nick Koston 326b3bf3ee Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 10:48:53 -05:00
J. Nick Koston 4e172a5774 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 10:48:53 -05:00
J. Nick Koston e4a54b27ed Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 10:48:53 -05:00
J. Nick Koston 7b3330d5fe Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-23 10:48:53 -05:00
J. Nick Koston e681c441d9 Close the residual idedata and size-summary silent-failure findings
A list-of-non-dicts compile DB now raises by name inside the best-effort
tuple. The launcher rejection moved into parse_entry itself so no caller
can record ccache as the compiler, and the shape key includes the entry's
directory since relative includes resolve against it. format_bar raises
on a non-positive total so every consumer must handle the meaningless
bar; the espidf summary validates the RAM region by name (a malformed
region can no longer suppress a computable Flash line) and the blanket
backstop logs the traceback at debug. A new test pins that the CI
trigger paths exist on disk, so a rename fails loudly.
2026-08-23 10:48:39 -05:00
J. Nick Koston af08a45afe Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 10:37:31 -05:00
J. Nick Koston 2e97689afb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 10:37:29 -05:00
J. Nick Koston 055b3ed198 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 10:37:27 -05:00
J. Nick Koston 115f8f6e4f Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 10:37:25 -05:00
J. Nick Koston f23b6072a9 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 10:37:23 -05:00
J. Nick Koston 0e28f0e399 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 10:37:21 -05:00
J. Nick Koston ec11e95b84 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 10:37:19 -05:00
J. Nick Koston 8cbb83a06d Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 10:37:16 -05:00
J. Nick Koston bac6530203 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 10:37:14 -05:00
J. Nick Koston 355d4788b8 Assert lexed tokens, not raw flag strings
shlex.quote wraps backslash paths on Windows, so the raw emitted strings
are platform-varying; lexing like the consumer does pins the behavior
that matters and passes on both separators.
2026-08-23 10:37:11 -05:00
J. Nick Koston caf758eaed Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-23 10:33:03 -05:00
J. Nick Koston 5bdb886190 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 10:33:03 -05:00
J. Nick Koston 8df7bc57de Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-23 10:33:03 -05:00
J. Nick Koston df71e76ce2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-23 10:33:03 -05:00
J. Nick Koston ee4b38eb4c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 10:33:03 -05:00
J. Nick Koston e39738f2fd Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 10:33:02 -05:00
J. Nick Koston d34d112a43 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 10:33:02 -05:00
J. Nick Koston b8dac2dc89 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 10:33:02 -05:00
J. Nick Koston 585d818e7a Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 10:33:02 -05:00
J. Nick Koston 80b492f638 Quote emitted -I/-L paths so spaced directories survive re-lexing
lex_build_flags shlex-splits build.flags, so an unquoted spaced path
became two garbage tokens; shlex.quote at the emit site round-trips it
back to one.
2026-08-23 10:31:59 -05:00
J. Nick Koston 33aac54c8f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp32/__init__.py
2026-08-23 10:17:28 -05:00
J. Nick Koston d6df22f7fa Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-23 10:17:10 -05:00
J. Nick Koston 707a9fc893 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec
# Conflicts:
#	esphome/helpers.py
#	tests/unit_tests/test_helpers.py
2026-08-23 10:17:07 -05:00
J. Nick Koston 759c6aecc9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-23 10:16:36 -05:00
J. Nick Koston 33e66a3a14 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-23 10:16:08 -05:00
J. Nick Koston 61fb0fdb6e Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-23 10:16:08 -05:00
J. Nick Koston 75f9007b77 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-23 10:16:07 -05:00
J. Nick Koston 692bb2a810 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-23 10:16:07 -05:00
J. Nick Koston 4a874a374a Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-23 10:16:06 -05:00
J. Nick Koston 54cd17591d Type-check extraScript, capture CPPPATH, surface version-less dependency drops
A non-string extraScript now fails naming the library instead of an opaque
TypeError, matching the hardening on every other manifest field. CPPPATH
joins the captured keys and translates to -I flags anchored like LIBPATH,
since the pipeline already routes -I to include dirs. Version-less
dependency drops log at INFO until the arduino-backend reconciliation
lands, and the wave-deferral comment now claims only what the guard
actually saves.
2026-08-23 10:15:52 -05:00
J. Nick Koston 98b595c95d Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-23 10:13:22 -05:00
J. Nick Koston e16cfded5d Merge remote-tracking branch 'origin/dev' into esp8266-native-idedata-helpers 2026-08-23 10:12:45 -05:00
J. Nick Koston 746b294ed7 Harden idedata against non-list compile DBs and stale caches, blanket the size summary
A compile DB that parses as valid JSON but is not a list now raises
EsphomeError inside IDEDATA_BEST_EFFORT_ERRORS instead of a TypeError that
fails an already-linked build. Cached idedata is validated on read against
the write path's guarantees (dict shape, no launcher as compiler, include
union present) so caches from older versions regenerate instead of serving
degraded data, and the served copy is re-stamped with the current ELF path.
Response-file shape sentinels key on the output object rather than the
source file, so two objects built from one source keep both include sets.

The size summary mirrors the standalone hardening PR: a blank partition
size cell raises by name, and a blanket guard keeps unexpected nested
shapes from raising past a build that already linked.
2026-08-23 10:12:40 -05:00
J. Nick Koston 2a2710d752 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:41:58 -05:00
J. Nick Koston c0be436a07 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:41:58 -05:00
J. Nick Koston 897ae28a19 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 23:41:58 -05:00
J. Nick Koston d2022c2ed9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 23:41:57 -05:00
J. Nick Koston 230b6926ab Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 23:41:57 -05:00
J. Nick Koston 4f315ae8ba Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 23:41:57 -05:00
J. Nick Koston 4e88823faf Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 23:41:57 -05:00
J. Nick Koston ec6123e0ef Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 23:41:57 -05:00
J. Nick Koston da3c6dec7f Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 23:41:56 -05:00
J. Nick Koston cfac36c647 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-22 23:41:56 -05:00
J. Nick Koston d179f43e7c Correct the zero-partition comment: the skip fails CI extraction loudly, it does not feed it 2026-08-22 23:41:55 -05:00
J. Nick Koston c7772c384e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:23:43 -05:00
J. Nick Koston 7248e59ca3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:23:43 -05:00
J. Nick Koston 8ec4393e3f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 23:23:41 -05:00
J. Nick Koston e842af8acb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 23:23:41 -05:00
J. Nick Koston ad2a3e120a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 23:23:41 -05:00
J. Nick Koston e5fcaf3892 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 23:23:40 -05:00
J. Nick Koston af16c444d4 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 23:23:40 -05:00
J. Nick Koston 327630523c Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 23:23:40 -05:00
J. Nick Koston 0e4f4237fd Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 23:23:40 -05:00
J. Nick Koston 96a74cd217 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-22 23:23:40 -05:00
J. Nick Koston dc64c93f39 [core] Register the OTA component in dummy_main like its siblings 2026-08-22 23:23:39 -05:00
J. Nick Koston 005aedd3a6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:21:08 -05:00
J. Nick Koston e25b6c4085 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:21:08 -05:00
J. Nick Koston 7bebe94e1c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 23:21:07 -05:00
J. Nick Koston a3beb8fb3d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 23:21:07 -05:00
J. Nick Koston d5e3d44fd4 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 23:21:07 -05:00
J. Nick Koston 32097fcb00 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 23:21:07 -05:00
J. Nick Koston 4bb0fa8761 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 23:21:07 -05:00
J. Nick Koston 1b109518f7 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 23:21:06 -05:00
J. Nick Koston 5793a5f08a Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 23:21:06 -05:00
J. Nick Koston 9d0d1b42d5 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-22 23:21:06 -05:00
J. Nick Koston 8230c16f12 Order the launcher strip before the empty guard, never dedupe rsp commands, harden the size summary 2026-08-22 23:21:04 -05:00
J. Nick Koston 3624ff6b19 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:10:58 -05:00
J. Nick Koston 57b5bb1b82 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:10:58 -05:00
J. Nick Koston dcc927f047 Mirror the damaged-file recovery tests into the chain 2026-08-22 23:10:58 -05:00
J. Nick Koston 505f4dee03 Mirror the damaged-file recovery tests into the chain 2026-08-22 23:10:37 -05:00
J. Nick Koston 1e5f7fe102 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:02:22 -05:00
J. Nick Koston ade226456e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:02:22 -05:00
J. Nick Koston bf547cd171 Recover only on decode errors; an OSError may hide an intact file 2026-08-22 23:02:20 -05:00
J. Nick Koston 6d3c78b5bc Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 23:00:19 -05:00
J. Nick Koston f326f7b527 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 23:00:19 -05:00
J. Nick Koston c6bd323b56 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 23:00:18 -05:00
J. Nick Koston 26941ef953 Capture INFO for the depends= visibility note 2026-08-22 23:00:03 -05:00
J. Nick Koston b302f4cb9a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:58:49 -05:00
J. Nick Koston fd077062c9 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 22:58:48 -05:00
J. Nick Koston a1d0713a54 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 22:58:48 -05:00
J. Nick Koston d37ebd5cd7 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 22:58:48 -05:00
J. Nick Koston e881502a25 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 22:58:48 -05:00
J. Nick Koston ef007e00d1 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 22:58:48 -05:00
J. Nick Koston 9e96d53868 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 22:58:47 -05:00
J. Nick Koston 905c806009 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 22:58:47 -05:00
J. Nick Koston 42f59f94c9 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 22:58:47 -05:00
J. Nick Koston 35bb8388a2 Defer superseded wave downloads, dedupe tool dests, validate captured buckets, right-size the log levels 2026-08-22 22:58:44 -05:00
J. Nick Koston 4b317deea3 Reconcile the provides() promise after resolving; name the double-warning invariant's pinning test 2026-08-22 22:54:56 -05:00
J. Nick Koston 1543709ddd Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:40:59 -05:00
J. Nick Koston c2c6cf9398 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 22:40:59 -05:00
J. Nick Koston 45617376ef Catch only EsphomeError; read_file wraps the decode error too 2026-08-22 22:40:48 -05:00
J. Nick Koston a424629ab6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:39:49 -05:00
J. Nick Koston b2111b5070 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 22:39:49 -05:00
J. Nick Koston a41dc7dfff Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 22:39:49 -05:00
J. Nick Koston 99ec278c67 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 22:39:48 -05:00
J. Nick Koston 6b7a56be67 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 22:39:48 -05:00
J. Nick Koston 6a0e7dc595 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 22:39:48 -05:00
J. Nick Koston 6fda5b9a07 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 22:39:48 -05:00
J. Nick Koston 9adba2ac06 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 22:39:48 -05:00
J. Nick Koston 5ac6e2b3c6 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 22:39:47 -05:00
J. Nick Koston b08026e413 Trigger the IDF infra job on the extraScript shim now that it exists 2026-08-22 22:39:34 -05:00
J. Nick Koston f6c6708f24 Merge branch 'esp8266-native-idedata-helpers' into esp8266-native-library-converter 2026-08-22 22:39:33 -05:00
J. Nick Koston 48c6948ae8 Guard empty compile commands, refuse a compile DB with no ESPHome TU, share the launcher rejection 2026-08-22 22:39:16 -05:00
J. Nick Koston d1299430bb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:32:38 -05:00
J. Nick Koston a75ea8225c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 22:32:38 -05:00
J. Nick Koston e10339a35e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 22:32:38 -05:00
J. Nick Koston 7445b47648 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 22:32:38 -05:00
J. Nick Koston f65aa87450 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 22:32:37 -05:00
J. Nick Koston 2dfa23f5e5 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 22:32:37 -05:00
J. Nick Koston e4911b4cc2 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 22:32:37 -05:00
J. Nick Koston e714ef4dfc Reconcile BOARDS with the generated table: d1_wroom_02 joins with its shipped flash layout 2026-08-22 22:32:26 -05:00
J. Nick Koston 538942153d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-08-22 22:30:05 -05:00
J. Nick Koston cd3cdde87c Preserve d1_wroom_02's shipped flash layout, refuse plain linker unflags, pin the real spaced-override outcome 2026-08-22 22:29:21 -05:00
J. Nick Koston 013a27bee9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:17:28 -05:00
J. Nick Koston 4577d69ca9 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 22:17:26 -05:00
J. Nick Koston 5a256abd65 Give the lwIP variants named fields 2026-08-22 22:17:02 -05:00
J. Nick Koston dce5185cef Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 22:11:45 -05:00
J. Nick Koston a7e5ac9dea Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 22:11:44 -05:00
J. Nick Koston be5317ae46 Scope the hex-only MMU rule to the segment sizes the surgery parser reads 2026-08-22 22:11:42 -05:00
J. Nick Koston 476852c84f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 22:11:14 -05:00
J. Nick Koston 2521f29782 Apply the 18559 simplify pass: surgery wrapper, shared clean hint, resilient write helper, unified knob lookups, test scaffolding 2026-08-22 22:09:36 -05:00
J. Nick Koston 4146f23ba3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 22:05:04 -05:00
J. Nick Koston f0203528f5 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 22:05:04 -05:00
J. Nick Koston cd291fb35b Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 22:05:04 -05:00
J. Nick Koston d2ed17b688 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 22:05:04 -05:00
J. Nick Koston e9466ff738 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 22:05:03 -05:00
J. Nick Koston b9317de2e8 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 22:05:03 -05:00
J. Nick Koston 4d6300b400 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 22:05:03 -05:00
J. Nick Koston 030e79fa5a Keep the empty-argument flag check next to the lexer that leaves the bare token 2026-08-22 22:04:47 -05:00
J. Nick Koston da9c0bdd14 Merge branch 'esp8266-native-library-converter' into esp8266-native-shared-helpers 2026-08-22 21:59:57 -05:00
J. Nick Koston a1e6370e8b [core] Harden the shared library converter and download registry archives in parallel 2026-08-22 21:59:19 -05:00
J. Nick Koston dada0f2c2b [core] Extract the shared idedata and size-summary helpers into build_helpers 2026-08-22 21:58:41 -05:00
J. Nick Koston 9fe10af350 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:55:44 -05:00
J. Nick Koston a5947beb07 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 21:55:44 -05:00
J. Nick Koston 9624c918e7 Hoist the invariant framework and arch define groups 2026-08-22 21:55:42 -05:00
J. Nick Koston 2fe3eaf97d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:50:50 -05:00
J. Nick Koston 2bfbc72147 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 21:50:38 -05:00
J. Nick Koston 4803ced57d Reunite the SDK-table comment with its table 2026-08-22 21:50:08 -05:00
J. Nick Koston 2c44df9efa Hoist the common linker-script names 2026-08-22 21:49:45 -05:00
J. Nick Koston aadc10944c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 21:49:06 -05:00
J. Nick Koston bb7ba38fd0 Hoist the knob tables to dicts and the shape checks to compiled module regexes 2026-08-22 21:48:41 -05:00
J. Nick Koston 24ea73a626 Gate the zero-test guard behind a flag, keep the upload path import-free, verify all artifacts, regenerate a stale compile DB 2026-08-22 21:47:03 -05:00
J. Nick Koston 9d4df93676 Assert the launcher string verbatim; Path normalization diverged on Windows 2026-08-22 21:42:53 -05:00
J. Nick Koston 390ca116bc Name the idedata consumers in the arduino backend's warning too 2026-08-22 21:42:15 -05:00
J. Nick Koston 2d325a9eee Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 21:42:14 -05:00
J. Nick Koston fbe5a02d6f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:42:14 -05:00
J. Nick Koston 9e3c84ff1b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 21:42:13 -05:00
J. Nick Koston c7d7a7ba75 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 21:41:58 -05:00
J. Nick Koston a5e87d3c8f Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 21:41:57 -05:00
J. Nick Koston ba1ad765ea Name the probe failure cause in the tool-version warning 2026-08-22 21:41:50 -05:00
J. Nick Koston 767bb61a14 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 21:41:28 -05:00
J. Nick Koston 21abf1692b Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 21:41:27 -05:00
J. Nick Koston a22c2a9768 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 21:41:27 -05:00
J. Nick Koston 18206967a1 Validate captured CPPDEFINES, warn on empty idedata includes, name the idedata consumers 2026-08-22 21:40:57 -05:00
J. Nick Koston beceab6327 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:30:41 -05:00
J. Nick Koston 822bb1d88f Drop the stale ccache_path patch from the write_project test 2026-08-22 21:29:50 -05:00
J. Nick Koston 9487cf6b7c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 21:29:33 -05:00
J. Nick Koston 81afaca560 Unify the MMU guards: hex-only sizes, every valued MMU_* validated, no-knob refuses all 2026-08-22 21:29:31 -05:00
J. Nick Koston 70765dd52a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 21:28:28 -05:00
J. Nick Koston 32a0fff6b8 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 21:28:28 -05:00
J. Nick Koston 586bc114fa Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 21:28:28 -05:00
J. Nick Koston 2f0ad8a57d Surface unexpected prefetch failures; restore the dropped cache-path rationales 2026-08-22 21:28:18 -05:00
J. Nick Koston 75150fda52 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 21:27:39 -05:00
J. Nick Koston 791e2b8204 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 21:27:39 -05:00
J. Nick Koston ce52b93249 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 21:27:39 -05:00
J. Nick Koston d9e18ee982 Support subscript env reads in extra scripts; make the INFO-capture fixture real 2026-08-22 21:27:31 -05:00
J. Nick Koston a003fb848a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:24:08 -05:00
J. Nick Koston e465839d17 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 21:24:08 -05:00
J. Nick Koston 319fdf6deb Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 21:24:08 -05:00
J. Nick Koston 13d1933873 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 21:24:07 -05:00
J. Nick Koston 44d447ada0 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 21:24:07 -05:00
J. Nick Koston f49a5879c3 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 21:24:07 -05:00
J. Nick Koston 918444ecbb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 21:24:07 -05:00
J. Nick Koston d26d3fdc33 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 21:24:06 -05:00
J. Nick Koston 227f5c67e2 Merge remote-tracking branch 'origin/dev' into esp8266-native-shared-helpers
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-22 21:23:40 -05:00
J. Nick Koston d43770b6d4 Drop a stale ccache_path patch from the write_project test 2026-08-22 21:22:41 -05:00
J. Nick Koston cc73c0c67e Dispatch esptool flashing via the backend hook, share the native trigger files, gate the probe, cache the closure 2026-08-22 21:21:25 -05:00
J. Nick Koston ff84e53ff1 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:19:00 -05:00
J. Nick Koston 0f3ac3b0e3 Point the board-check comment at the validator that now exists 2026-08-22 21:18:58 -05:00
J. Nick Koston aa63eb9734 Move the resolve-for-me ccache sentinel to its one consumer 2026-08-22 21:18:48 -05:00
J. Nick Koston 9144ae462d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 21:17:55 -05:00
J. Nick Koston ec3f7fb411 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 21:17:54 -05:00
J. Nick Koston aa5700d150 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 21:17:54 -05:00
J. Nick Koston c15df918f5 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-22 21:17:37 -05:00
J. Nick Koston 3d540b1597 Require a resolved ccache, dedupe the package specs, use the shared cache spec 2026-08-22 21:16:27 -05:00
J. Nick Koston ca79cb1a20 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer
# Conflicts:
#	esphome/writer.py
2026-08-22 21:14:48 -05:00
J. Nick Koston e557e84468 Route the registry prefetch through the shared downloader; register tools caches in one table 2026-08-22 21:14:18 -05:00
J. Nick Koston 5c30acfe5b Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 21:12:39 -05:00
J. Nick Koston cc27854fb2 Point the consumed-options comment at its now-real consumer 2026-08-22 21:12:37 -05:00
J. Nick Koston 044d593f09 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 21:12:36 -05:00
J. Nick Koston 68e04f5982 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 21:12:36 -05:00
J. Nick Koston d6d80ee323 Consolidate the batch-download scaffold, share the idedata error set, dedupe compdb tokenizing 2026-08-22 21:12:20 -05:00
J. Nick Koston 64d0137ab8 Verify build artifacts and surface probe diagnostics; fail on a zero-test CI run 2026-08-22 20:49:02 -05:00
J. Nick Koston 53cfdc92ba Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 20:26:38 -05:00
J. Nick Koston 13ae59378d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 20:26:38 -05:00
J. Nick Koston c60b8d1b8b Validate custom MMU sizes, refuse raw NONOSDK defines, warn on a lost stderr note 2026-08-22 20:26:27 -05:00
J. Nick Koston 1b0d20e72e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 20:13:48 -05:00
J. Nick Koston 72b37a0bf2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 20:13:48 -05:00
J. Nick Koston 378d5f53e3 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 20:13:48 -05:00
J. Nick Koston fa5d1c57f9 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 20:13:48 -05:00
J. Nick Koston 2218743c4a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 20:13:47 -05:00
J. Nick Koston de709dec71 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 20:13:47 -05:00
J. Nick Koston 2e3dc3c514 Note the consumed-options export is unused until the backend lands 2026-08-22 20:13:45 -05:00
J. Nick Koston 0dfe029863 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 20:01:32 -05:00
J. Nick Koston 7460f8df1a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 20:01:32 -05:00
J. Nick Koston eeb26a375f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 20:01:32 -05:00
J. Nick Koston 33987c9682 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 20:01:32 -05:00
J. Nick Koston 149ca8c954 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 20:01:31 -05:00
J. Nick Koston 45c4a9b143 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 20:01:31 -05:00
J. Nick Koston bf0a4ea40f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 20:01:31 -05:00
J. Nick Koston 0d33c3bf07 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 20:01:31 -05:00
J. Nick Koston 2acba9b364 Materialize the tracker mock before the prefetch threads race its creation 2026-08-22 20:01:13 -05:00
J. Nick Koston 8b8ef9bc61 Clean up the archive on any ar failure; state the link-order contract plainly 2026-08-22 20:00:22 -05:00
J. Nick Koston 4fa3ad4381 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 19:55:34 -05:00
J. Nick Koston 19bb36c7ff Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 19:55:34 -05:00
J. Nick Koston f9e3caeeff Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 19:55:34 -05:00
J. Nick Koston 36b0b62a8f Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 19:55:33 -05:00
J. Nick Koston a174c306d8 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 19:55:33 -05:00
J. Nick Koston 35f3087fcc Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 19:55:33 -05:00
J. Nick Koston 8475a4bf09 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 19:55:33 -05:00
J. Nick Koston 715a7ab58f Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 19:55:33 -05:00
J. Nick Koston f4bc7dda35 Fault the cache read directly so the unreadable-cache test holds on Windows 2026-08-22 19:55:16 -05:00
J. Nick Koston a80db169a4 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 19:46:47 -05:00
J. Nick Koston 93ce8ac58e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 19:46:46 -05:00
J. Nick Koston eff99be8fa Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 19:46:46 -05:00
J. Nick Koston 3e4ace6b84 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 19:46:46 -05:00
J. Nick Koston d72e2f1c60 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 19:46:46 -05:00
J. Nick Koston 5ba4dc7704 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 19:46:46 -05:00
J. Nick Koston cbbc0a8fa9 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 19:46:45 -05:00
J. Nick Koston 1f0fa0ef8b Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 19:46:45 -05:00
J. Nick Koston 7d246893be Surface prefetch failures, harden the idedata and build-info cache reads 2026-08-22 19:46:42 -05:00
J. Nick Koston cf5fd1f36a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 19:32:13 -05:00
J. Nick Koston 84376f0da6 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 19:32:13 -05:00
J. Nick Koston a401567f08 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 19:32:13 -05:00
J. Nick Koston 225c3f4cdb Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 19:32:13 -05:00
J. Nick Koston ce3f90d377 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 19:32:13 -05:00
J. Nick Koston 3697401bc7 Serialize prefetch downloads on the install lock; export the canonical ccache off spelling 2026-08-22 19:32:10 -05:00
J. Nick Koston 4aafc96ef7 Pin the analyze-memory ELF guard in tests 2026-08-22 19:18:13 -05:00
J. Nick Koston 2af06e3b53 Use the exported consumed-options set, guard the analyze-memory ELF, trigger on the cache action 2026-08-22 19:16:50 -05:00
J. Nick Koston c26f77fe62 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 19:15:09 -05:00
J. Nick Koston c3eeb3fa2a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-22 19:15:07 -05:00
J. Nick Koston c7efd89a3d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 19:14:41 -05:00
J. Nick Koston c3297c2663 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 19:14:41 -05:00
J. Nick Koston 7be255b9ba Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 19:14:41 -05:00
J. Nick Koston c3129d598c Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 19:14:41 -05:00
J. Nick Koston 82b20313b0 Export the consumed platformio_options set so the ignored-option warning cannot drift 2026-08-22 19:14:32 -05:00
J. Nick Koston 03dba8b63e Raise on empty-argument build flags, pin the preprocessor decode, soften bookkeeping writes 2026-08-22 19:13:41 -05:00
J. Nick Koston b5219d3c60 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 17:24:38 -05:00
J. Nick Koston 050aa1ea21 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 17:24:38 -05:00
J. Nick Koston 09d349882e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 17:24:38 -05:00
J. Nick Koston 2a1af47cef Normalize git tails in external short names; surface the name-match suppressions 2026-08-22 17:24:26 -05:00
J. Nick Koston 7e8b033860 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 17:10:24 -05:00
J. Nick Koston a7fe085e87 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 17:10:24 -05:00
J. Nick Koston aa3330071a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 17:10:24 -05:00
J. Nick Koston 27aef88077 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 17:10:23 -05:00
J. Nick Koston a5fde9429d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 17:10:23 -05:00
J. Nick Koston e63d995d1f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 17:10:23 -05:00
J. Nick Koston ad0859c5bd Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 17:10:23 -05:00
J. Nick Koston 385e2a92d2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 17:10:23 -05:00
J. Nick Koston bff8bea83e Degrade garbage Content-Length probes; never prefetch an unverifiable tool archive 2026-08-22 17:10:19 -05:00
J. Nick Koston aaf27d0e90 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 16:59:09 -05:00
J. Nick Koston a143d192c5 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 16:59:09 -05:00
J. Nick Koston beb605a2d7 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 16:59:09 -05:00
J. Nick Koston f3ae985f67 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 16:59:09 -05:00
J. Nick Koston 0c5586c7dc Download the Arduino core and toolchain archives in parallel 2026-08-22 16:59:07 -05:00
J. Nick Koston 4ece0da68c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 16:58:37 -05:00
J. Nick Koston 712ee229e5 Prefetch pending registry packages in parallel under one combined bar 2026-08-22 16:58:24 -05:00
J. Nick Koston b5fbb767c2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 16:41:54 -05:00
J. Nick Koston e9c2363a38 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 16:41:53 -05:00
J. Nick Koston 727197d07a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 16:41:53 -05:00
J. Nick Koston 0df7736d75 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 16:41:53 -05:00
J. Nick Koston 80c9c4cef3 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 16:41:53 -05:00
J. Nick Koston bc98ba3b46 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 16:41:52 -05:00
J. Nick Koston 3974a810bc Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 16:41:52 -05:00
J. Nick Koston dcf921d5f6 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 16:41:52 -05:00
J. Nick Koston 49d060fdfd Correct the _content_lengths contract docs and pin the unknown-size fallback 2026-08-22 16:41:40 -05:00
J. Nick Koston e3d731b1df Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 16:38:32 -05:00
J. Nick Koston 39d18e7411 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 16:38:31 -05:00
J. Nick Koston 23fc61d9b1 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 16:38:31 -05:00
J. Nick Koston f4844e2d69 Accept precompiled=false, keep same-file copies intact, ungate the empty-match warning 2026-08-22 16:38:21 -05:00
J. Nick Koston 53fb66616c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 16:16:23 -05:00
J. Nick Koston 0ace5d0415 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 16:16:23 -05:00
J. Nick Koston 8f3e9f97c0 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 16:16:23 -05:00
J. Nick Koston f1c751c3b4 Rename the link-field guard to match its raising behavior 2026-08-22 16:16:14 -05:00
J. Nick Koston 3219f02e23 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/__main__.py
2026-08-22 16:10:47 -05:00
J. Nick Koston b024fd53dd Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 16:10:10 -05:00
J. Nick Koston 466d67788e Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 16:10:09 -05:00
J. Nick Koston f2f5ea127e Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 16:10:09 -05:00
J. Nick Koston a4c1c89e67 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 16:10:09 -05:00
J. Nick Koston ebafc439ac Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 16:10:09 -05:00
J. Nick Koston 2acde317d2 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 16:10:08 -05:00
J. Nick Koston d1d2f186ab Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 16:10:08 -05:00
J. Nick Koston f2ff1cc986 Keep per-file bars when sizes are unknown; harden the prefetch probes
An unknown Content-Length (probe failure, non-2xx, or a CDN omitting it
on HEAD) now skips the parallel prefetch so the sequential downloads
keep their per-file bars, instead of a silent multi-MB batch; the HEAD
helper returns None for unknown, distinct from a genuine zero, and
catches only RequestException. The cache probe logs its failure at
debug. The espidf tool prefetch reads sizes with .get so a missing size
only drops the bar instead of aborting the resumable prefetch. The
idedata warning logs its traceback at debug for parser regressions, and
framework_helpers joins the ESP-IDF infra CI triggers it is imported
by.
2026-08-22 16:10:03 -05:00
J. Nick Koston 5681890f74 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:58:12 -05:00
J. Nick Koston 7d51911102 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:58:11 -05:00
J. Nick Koston 792685facf Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:58:11 -05:00
J. Nick Koston 77704c0909 Refuse unsupported manifest features by name; drop the dead warn branch
A bundled manifest relying on an extraScript, or any manifest declaring
precompiled/ldflags, now raises naming the library instead of warning
into a link failure far from the cause. The backend-side usability
re-check logs all InvalidLibrary causes at debug with an accurate
comment: the walk runs dependency_is_usable on every versioned entry
before the provides() skip, so the fault always warns there first (a
real-converter test pins the once-only warning). build_tool handles a
missing subcommand with its named error instead of an IndexError.
2026-08-22 15:57:30 -05:00
J. Nick Koston 5ae3009791 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:51:43 -05:00
J. Nick Koston 11964b86a8 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 15:51:42 -05:00
J. Nick Koston 3f006545c1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:51:42 -05:00
J. Nick Koston 1a64f03994 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:51:42 -05:00
J. Nick Koston f8484158ad Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 15:51:42 -05:00
J. Nick Koston a7777e4589 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 15:51:41 -05:00
J. Nick Koston 4e6a8e297e Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 15:51:41 -05:00
J. Nick Koston 2315f54f2e Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 15:51:41 -05:00
J. Nick Koston 86ac8f661b Fold the dependency-entry validation into one helper
The name and version checks were duplicated across the dict-shorthand
and list spellings with four identical warnings; _valid_dependency_entry
carries them once.
2026-08-22 15:51:38 -05:00
J. Nick Koston a97479105f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:47:13 -05:00
J. Nick Koston a2e4664e87 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:47:12 -05:00
J. Nick Koston 9d38ac8d6c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:47:12 -05:00
J. Nick Koston 7694ffb5ac Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-22 15:47:09 -05:00
J. Nick Koston 7f6aaeb46c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 15:46:47 -05:00
J. Nick Koston 7a938af0f8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 15:46:47 -05:00
J. Nick Koston 689861ffc9 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 15:46:47 -05:00
J. Nick Koston 776b3844f9 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 15:46:47 -05:00
J. Nick Koston eec01ea793 Diagnosable prefetch failures, Ctrl-C-safe pool, typed dependency versions
The library prefetch pool now cancels queued futures on interrupt like
the espidf pool it mirrors, prefetch and HEAD failures log their cause
at debug (a suppressed bar is traceable), and non-2xx HEAD statuses read
as unknown size. normalize_dependencies rejects a non-string version in
both spellings (a container would raise from set.add(); an int fails
opaquely in the registry), and the walk's version-less skip logs the
dependency at debug until the arduino-backend reconciliation lands.
2026-08-22 15:46:38 -05:00
J. Nick Koston b888d41cb9 Diagnosable prefetch failures, Ctrl-C-safe pool, typed dependency versions
The library prefetch pool now cancels queued futures on interrupt like
the espidf pool it mirrors, prefetch and HEAD failures log their cause
at debug (a suppressed bar is traceable), and non-2xx HEAD statuses read
as unknown size. normalize_dependencies rejects a non-string version in
both spellings (a container would raise from set.add(); an int fails
opaquely in the registry), and the walk's version-less skip logs the
dependency at debug until the arduino-backend reconciliation lands.
2026-08-22 15:46:06 -05:00
J. Nick Koston 3635c05fa5 Non-destructive platform_version check, honest compdb errors, missing-binutils refusal
The platform_version pop defaults to the schema spec so a second
validation pass over an already-validated dict cannot warn about a key
the user never set. An unparsable compile database now fails naming the
parse error and the offending output instead of blaming renamed ninja
rules. analyze-memory validates the native objdump/readelf exist and
fails by tool name rather than silently analyzing with host binutils.
The shared smoke-test helper is renamed _toolchain_components_to_test
(it serves the esp32 PlatformIO job too), and the decode-dedup state is
cleared by an autouse fixture instead of by hand.
2026-08-22 15:36:49 -05:00
J. Nick Koston 51ae50cb27 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:33:41 -05:00
J. Nick Koston 77915bd03e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:33:41 -05:00
J. Nick Koston 160299a41e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:33:41 -05:00
J. Nick Koston 8b76d61e8f Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 15:33:40 -05:00
J. Nick Koston 8bcf42921a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 15:33:40 -05:00
J. Nick Koston b3f058613c Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 15:33:40 -05:00
J. Nick Koston 97701122be Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 15:33:40 -05:00
J. Nick Koston f1d043c840 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 15:33:40 -05:00
J. Nick Koston 1eda5a8534 Skip already-cached archives in the download prefetch
The wave logged 'Downloading N libraries' before checking the
extraction markers, so a warm build announced downloads it never made.
URLSource gains an is_cached probe (best-effort in the prefetch) and a
fully warm wave stays silent.
2026-08-22 15:33:37 -05:00
J. Nick Koston 0910604166 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:25:48 -05:00
J. Nick Koston db89d64c4e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:25:48 -05:00
J. Nick Koston 3641621b0e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:25:48 -05:00
J. Nick Koston 040c91259d Mirror the URL rule in the bundled probe; fail on empty converted trees; harden build_tool argv
A URL-pinned dependency now skips the bundled probe (the walk resolves
the fork; adding the bundled copy would double the archive). A versioned
bundled candidate's non-platform manifest fault warns here since it
skips the walk's usability filter via provides(); version-less causes
stay at debug (the walk already warned). The pending drain logs a
manifest-name suppression at debug and drops its unreachable
bundled_names re-check. A converted tree with no sources and no headers
now fails by name at emit like the bundled case (test scaffolds gained
real source files). build_tool validates each mode's operand count and
a failed copy unlinks the partial output.
2026-08-22 15:25:37 -05:00
J. Nick Koston 1652088009 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 15:21:04 -05:00
J. Nick Koston ff8f9786e9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 15:21:04 -05:00
J. Nick Koston 4cbfdd3200 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra
# Conflicts:
#	tests/unit_tests/test_framework_helpers.py
2026-08-22 15:21:01 -05:00
J. Nick Koston 520bf3f63b Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 15:20:42 -05:00
J. Nick Koston 1f2b532394 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 15:20:42 -05:00
J. Nick Koston 1cf5df3d59 Merge the espidf parallel-prefetch branch and give library downloads its combined bar
Brings in #18513 (BatchDownloadProgress and the download_with_resume
progress callback) and extends the plumbing one level:
download_from_mirrors passes a progress callback to both target kinds,
Source/ConvertedLibrary.download thread it through, and the library
wave prefetch draws one combined bar sized by parallel HEAD requests
(no sizes, no bar). The thread-local bar suppression this replaces is
removed; a batch caller passing a tracker also owns the messaging, so
the per-file Downloading line only prints for solo downloads.
2026-08-22 15:19:58 -05:00
J. Nick Koston e8dea9b07f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:10:17 -05:00
J. Nick Koston 2e570bdc02 Correct the board-check comment; note the override behavior of get_flash_ld_path 2026-08-22 15:10:14 -05:00
J. Nick Koston e00229d22c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:06:32 -05:00
J. Nick Koston 7c47cbdb73 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 15:06:30 -05:00
J. Nick Koston 49dcc89130 Validate the board and flash-ld names; reject valued VTABLES defines; scope the damaged-cache recovery
The board name lands unquoted in two -D bodies and the flash linker
script name joins under the SDK and build ld dirs, so both are now
shape-validated like f_cpu. A VTABLES_IN_* define carrying a body would
split the compile line from the linker script and is refused. The
damaged-cache overwrite moves into a shared _write_generated helper
scoped to the comparison read: a corrupt existing copy is logged and
replaced (the testing-mode flash ld gets the same recovery), while a
genuine write failure still raises with its cause.
2026-08-22 15:05:58 -05:00
J. Nick Koston ae38e587fa Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 15:03:22 -05:00
J. Nick Koston a2a93cc186 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 15:03:21 -05:00
J. Nick Koston ae141a4712 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 15:03:21 -05:00
J. Nick Koston 6171561b70 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 15:03:21 -05:00
J. Nick Koston b29fbe5839 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 15:03:21 -05:00
J. Nick Koston 58eea37e10 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 15:03:21 -05:00
J. Nick Koston 91836a8c69 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 15:03:20 -05:00
J. Nick Koston 35af304911 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 15:03:20 -05:00
J. Nick Koston f4482275cb Pin sortedness on a nested fixture in the comment-order test 2026-08-22 15:03:07 -05:00
J. Nick Koston 298c78ff09 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:54:58 -05:00
J. Nick Koston 4aba6c4670 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:54:58 -05:00
J. Nick Koston 5f2d0b9e93 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:54:58 -05:00
J. Nick Koston 4ebdd88d7b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:54:58 -05:00
J. Nick Koston 241e804879 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:54:58 -05:00
J. Nick Koston d653a550bb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:54:57 -05:00
J. Nick Koston f599e37375 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:54:57 -05:00
J. Nick Koston 6f79518ee2 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:54:57 -05:00
J. Nick Koston fd7e340e81 Type-hint the to_code test stub 2026-08-22 14:54:39 -05:00
J. Nick Koston 84a8ac3772 Use a docstring instead of pass in the to_code test stub 2026-08-22 14:54:24 -05:00
J. Nick Koston 2c6cbdef4d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:52:41 -05:00
J. Nick Koston 961bff4790 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:52:40 -05:00
J. Nick Koston 469fd5b2c4 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:52:40 -05:00
J. Nick Koston 9f64d54e50 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:52:40 -05:00
J. Nick Koston 9be1a67400 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:52:40 -05:00
J. Nick Koston cb02e15184 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:52:40 -05:00
J. Nick Koston 910147139a Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:52:39 -05:00
J. Nick Koston ab49aff931 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:52:39 -05:00
J. Nick Koston 4a459e3d0d Lift the remaining function-local imports in test_main to top level 2026-08-22 14:52:38 -05:00
J. Nick Koston 612775908e Never substitute a URL-pinned dependency; rename the header-suffix set; warn on real bundled suppression
A dependency whose version is a repository URL names one specific
source, so it is now detected before the backend-provided skip and
resolves as git instead of being replaced by the bundled copy. The
library header-suffix set becomes LIBRARY_HEADER_SUFFIXES so it cannot
shadow esphome.const's narrower HEADER_FILE_EXTENSIONS. Suppressing a
genuinely bundled name on an external short-name match warns (an
accidental collision would surface as link errors), a converted library
with no sources and no headers warns by name, and the walk's
unreachable nameless-dependency check is gone.
2026-08-22 14:52:07 -05:00
J. Nick Koston 680753dbef Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-22 14:50:04 -05:00
J. Nick Koston 8a4ade10e6 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:49:42 -05:00
J. Nick Koston 8cffd44ffd Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:49:42 -05:00
J. Nick Koston e16008fc58 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:49:42 -05:00
J. Nick Koston 35a1136bea Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:49:41 -05:00
J. Nick Koston 3b091676bf Drop the unreachable nameless-dependency check in the walk
normalize_dependencies guarantees every entry carries a non-empty
string name, so only the version can be absent.
2026-08-22 14:49:39 -05:00
J. Nick Koston 4d9da7284e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:44:18 -05:00
J. Nick Koston fd82f0f4bf Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:44:18 -05:00
J. Nick Koston 0883b6e5aa Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:44:18 -05:00
J. Nick Koston ef93ebb67b Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:44:17 -05:00
J. Nick Koston 622be18709 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:44:17 -05:00
J. Nick Koston ade6dbabae Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:44:17 -05:00
J. Nick Koston 182dc7f636 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:44:17 -05:00
J. Nick Koston d7af5f37b6 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:44:17 -05:00
J. Nick Koston 121795fa8d Trim comment and docstring essays 2026-08-22 14:44:12 -05:00
J. Nick Koston 28107bf966 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:41:35 -05:00
J. Nick Koston 594cc89b38 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:41:34 -05:00
J. Nick Koston 8fb771eec8 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:41:34 -05:00
J. Nick Koston 38be558603 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:41:34 -05:00
J. Nick Koston 4e48764bbe Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:41:34 -05:00
J. Nick Koston deecfade13 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:41:34 -05:00
J. Nick Koston ec237a2d06 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:41:33 -05:00
J. Nick Koston a2267eb686 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:41:33 -05:00
J. Nick Koston dbd6f323c0 Extract the build-info staleness check so its branches are testable
copy_src_tree is always mocked in the writer tests, so the new
missing/stale/unreadable debug branches were unreachable; the decision
moves into _build_info_stale with a test covering every branch.
2026-08-22 14:41:30 -05:00
J. Nick Koston 23bc88355b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:38:09 -05:00
J. Nick Koston 342b61ef84 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:38:09 -05:00
J. Nick Koston 2903aa7c3e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:38:09 -05:00
J. Nick Koston e4cb1d4f27 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:38:09 -05:00
J. Nick Koston 62a4cb3fe4 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:38:09 -05:00
J. Nick Koston d3eaac6f47 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:38:08 -05:00
J. Nick Koston 2eec194d87 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-22 14:38:04 -05:00
J. Nick Koston 3a9a6edc0e Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:37:46 -05:00
J. Nick Koston 11875ec040 Dump the main.cpp config comment with sorted keys
voluptuous fills schema defaults in set-iteration order, so the
validated dict's key order changes with the process hash seed; the
unsorted dump churned the comment block in main.cpp and relinked the
firmware on every esphome run for any config using a defaults-heavy
action (logger.log in a button's on_press was enough). Affects the
PlatformIO path identically.
2026-08-22 14:37:42 -05:00
J. Nick Koston 42134329e3 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:31:40 -05:00
J. Nick Koston f9f642b81d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:31:39 -05:00
J. Nick Koston 2e9ba5fa2d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:31:39 -05:00
J. Nick Koston eddb5981da Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 14:31:39 -05:00
J. Nick Koston 51221688f6 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:31:39 -05:00
J. Nick Koston f695e9dceb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 14:31:39 -05:00
J. Nick Koston d8f6368716 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:31:38 -05:00
J. Nick Koston a97b836012 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:31:38 -05:00
J. Nick Koston afeb1a5ea1 Name the changed source when the writer flags a rebuild
Every sources_changed site now logs which file (or which build-info
staleness) triggered it, so a config that relinks on every run can be
diagnosed from one -v compile instead of diffing the build tree.
2026-08-22 14:31:36 -05:00
J. Nick Koston 57248d3d6f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:21:11 -05:00
J. Nick Koston 007cd61fe4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:21:11 -05:00
J. Nick Koston b435bb9d4f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:21:11 -05:00
J. Nick Koston 557ba9953d Fail by name on a missing libraries dir; single frameworks warning; fix a vacuous test
A framework tree without libraries/ now raises naming the path instead
of silently rerouting every bundled name to the registry, matching the
empty-bundled-dir error. check_library_data accepts framework=None to
skip the framework check (mirroring platform=None), so the backend-side
platform re-check no longer re-fires the frameworks-mismatch warning
the walk already emitted. The platform-rejection-is-debug test patched
the wrong module and asserted nothing; it now patches the backend's
import and asserts the dependency is absent from the resolved set.
2026-08-22 14:21:08 -05:00
J. Nick Koston 1d88a5a92b Keep no-op rebuilds quiet
A -n dry-run probe answers 'no work to do' without the real ninja spawn,
and running with cwd instead of -C drops the 'Entering directory' banner
on real builds too.
2026-08-22 14:14:37 -05:00
J. Nick Koston 3985ca5d51 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 14:12:57 -05:00
J. Nick Koston b247df7692 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 14:12:57 -05:00
J. Nick Koston 0e1c7cbb7e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 14:12:57 -05:00
J. Nick Koston a890527ab3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-22 14:12:54 -05:00
J. Nick Koston 2d2750e031 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 14:11:40 -05:00
J. Nick Koston 0d508ccbc0 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra
# Conflicts:
#	tests/unit_tests/test_framework_helpers.py
2026-08-22 14:11:26 -05:00
J. Nick Koston bf7a617934 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 14:11:02 -05:00
J. Nick Koston 803eef7de6 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 14:11:02 -05:00
J. Nick Koston fb06b4d631 Download a wave of registry libraries in parallel
The walk now drains its frontier, prefetches the wave's registry
archives with a small thread pool (deduped by URL, progress bars
suppressed per thread since parallel bars would interleave), and then
processes the wave sequentially; the sequential download() call stays
authoritative so failures surface with resume exactly as before. Same
approach as the espidf tool prefetch in #18513.
2026-08-22 14:10:40 -05:00
J. Nick Koston eb62957b66 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 13:51:48 -05:00
J. Nick Koston 2a86ae572d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 13:51:48 -05:00
J. Nick Koston 7fe793da17 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 13:51:48 -05:00
J. Nick Koston 447a411d45 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 13:51:48 -05:00
J. Nick Koston ae2893992a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 13:51:47 -05:00
J. Nick Koston 6b46e9fd03 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 13:51:47 -05:00
J. Nick Koston 2f053371ce Guard the honored board_build branch against the empty-list form
voluptuous accepts [] for [cv.string], so vals[-1] could raise an
IndexError at codegen time; an empty list now falls through to the
ignored-option warning.
2026-08-22 13:51:35 -05:00
J. Nick Koston 47e87d7eb2 Dedupe the rejection warning and make bundled-name membership case-exact
The backend-side bundled filter now checks compatibility silently (the
shared walk owns the warning), so one manifest fault warns once instead
of twice. Bundled-name membership uses the exact on-disk directory
names instead of a per-name is_dir() probe, so a case-insensitive
filesystem cannot match a case-mismatched dependency and build the same
bundled library twice.
2026-08-22 13:50:29 -05:00
J. Nick Koston 255ca06325 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 13:16:00 -05:00
J. Nick Koston 893ec5d3f5 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 13:16:00 -05:00
J. Nick Koston a4a566eac2 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 13:15:59 -05:00
J. Nick Koston 3bd4cdb760 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 13:15:59 -05:00
J. Nick Koston 9533c09b69 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 13:15:59 -05:00
J. Nick Koston 2ea5c87e99 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 13:15:59 -05:00
J. Nick Koston 2dac9112be Pin the scalar shape for the honored board_build options; note the dispatch coupling
The schema permits the list form, so the routing now stores the last
value (like a later platformio.ini line) and the generator always sees a
scalar. The using_native_toolchain docstring points at write_cpp_file's
dispatch so NATIVE_TOOLCHAINS membership and the project-writing branch
flip together.
2026-08-22 13:15:47 -05:00
J. Nick Koston e8ceb241e1 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 13:10:55 -05:00
J. Nick Koston c8dd9dd483 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 13:10:55 -05:00
J. Nick Koston a9149aef28 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 13:10:55 -05:00
J. Nick Koston efa3018123 Close the four diagnostic gaps in the library backend
An owner-qualified dependency name (Owner/Pkg, both halves safe) is the
converter's to resolve and no longer draws the malformed-entry warning,
which stays for genuinely unsafe shapes. A declared srcFilter matching
only inert files now warns like one matching nothing, while matched
headers still read as a header-only library. The short-name suppression
logs the assumed external at debug so an accidental collision is
attributable. A failing ar batch unlinks the truncated archive before
returning its exit code.
2026-08-22 13:10:44 -05:00
J. Nick Koston ac227b552c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 12:52:53 -05:00
J. Nick Koston efe2dc481d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 12:52:53 -05:00
J. Nick Koston aa2cd99a9b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 12:52:53 -05:00
J. Nick Koston 478584354e Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 12:52:52 -05:00
J. Nick Koston 53228c183a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 12:52:52 -05:00
J. Nick Koston 9c7f68b813 Hoist the boolean spelling tables to helpers so cv.boolean and the env parser share one source
cv.boolean's inline tuples and the ccache env tables were two copies of
the same spellings; TRUTHY_BOOL_STRINGS/FALSY_BOOL_STRINGS now live in
esphome/helpers.py, cv.boolean consumes them, and parse_enable_env
derives its tables by adding the 1/0 env convention.
2026-08-22 12:52:38 -05:00
J. Nick Koston fe357106df Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 12:48:21 -05:00
J. Nick Koston 751914c47f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 12:48:21 -05:00
J. Nick Koston f4f7492f37 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 12:48:21 -05:00
J. Nick Koston ef6c609e93 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	tests/unit_tests/test_platformio_library.py
2026-08-22 12:47:48 -05:00
J. Nick Koston b62d59ca26 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 12:47:07 -05:00
J. Nick Koston e52703617e Name the env boolean spelling tables like device-builder does
parse_enable_env's inline tuples become TRUTHY_ENV_STRINGS and
FALSY_ENV_STRINGS frozensets mirroring cv.boolean's spellings (enable
and disable included) plus the 1/0 env convention, matching
device-builder's TRUTHY_BOOL_STRINGS pattern.
2026-08-22 12:47:05 -05:00
J. Nick Koston 57cbadbe9f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 12:46:30 -05:00
J. Nick Koston a6ca775a48 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 12:46:29 -05:00
J. Nick Koston 315f41e884 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 12:46:29 -05:00
J. Nick Koston 65609bb94b Move the backend-agnostic library hardening down from the arduino backend PR
The typed IncompatiblePlatform exception, dependency_is_usable,
warn_properties_depends, the lex_build_flags helper (espidf switches to
it), the normalize_dependencies validation, the manifest shape check,
the component-level drop-warning split, and the SCons case-sensitive
.C/.C++ suffixes all harden the shared converter independently of the
arduino backend, so they belong in this PR; the provides hook and the
version-less reconciliation stay with the backend that needs them.
2026-08-22 12:46:16 -05:00
J. Nick Koston 09a875f359 Refactor the library backend into focused functions
build_tool gains one function per mode plus a shared rspfile reader.
_library_info becomes an orchestrator over _resolve_src_dir,
_resolve_lib_archive, _classify_build_flags, _resolve_include_dirs, and
_collect_lib_sources. The version-less reconciliation moves into
_warn_unsatisfied_versionless. _is_safe_library_name switches from a
character denylist to a filename-plain allowlist, which excludes
separators, drive colons, and dot-only names by shape.
2026-08-22 12:43:04 -05:00
J. Nick Koston 43411106bb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 12:26:39 -05:00
J. Nick Koston e107747643 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 12:26:39 -05:00
J. Nick Koston 01f7373d51 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 12:26:39 -05:00
J. Nick Koston 6bdec7e907 Warn only for source-like suffix drops, batch ar argv, name non-iterable dependencies
The unmapped-suffix warning fired for every header-only library (the
default +<*> filter matches headers), so ArduinoJson would have warned
on every ESP8266 build. It now names exactly the source-like files
(.CPP, .ino and case-variants of the map) the case-sensitive suffix map
rejects, partial drops included, and stays quiet for headers and
metadata.

The ar shim batches the expanded object list by argv length (rc then q
appends), keeping the command line under the Windows 32767-char limit
the rspfile existed to avoid. A non-iterable dependencies value in a
manifest now warns by library name instead of raising a bare
TypeError.
2026-08-22 12:26:24 -05:00
J. Nick Koston e41440b16b Tilde-expand the install prefix before the CI cache-path assertion
The job env carries a literal ~ that Python's expanduser and
actions/cache both resolve; the assertion compared the raw string and
failed the native toolchain job.
2026-08-22 12:23:24 -05:00
J. Nick Koston 19d8f832b9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	esphome/components/esp8266/__init__.py
2026-08-22 12:16:27 -05:00
J. Nick Koston d7edb52c7b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 12:15:40 -05:00
J. Nick Koston 4a1138820d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 12:15:39 -05:00
J. Nick Koston 2ab0dc4e4f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 12:15:39 -05:00
J. Nick Koston bbcc9f690a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 12:15:39 -05:00
J. Nick Koston 7c07276c71 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 12:15:38 -05:00
J. Nick Koston 60cf44de3b Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 12:15:38 -05:00
J. Nick Koston 072b65c0e2 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 12:15:38 -05:00
J. Nick Koston f71867ed2d Merge remote-tracking branch 'origin/dev' into esp8266-native-shared-helpers 2026-08-22 12:15:30 -05:00
J. Nick Koston 8b7d199ff9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 12:08:57 -05:00
J. Nick Koston e7aa269346 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 12:08:57 -05:00
J. Nick Koston 3037ed0a28 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 12:08:57 -05:00
J. Nick Koston c206f83528 Make the remaining silent drops visible across backends
The depends=-without-dependencies warning moves into the shared walk so
espidf builds report it too; the arduino backend keeps it only for
bundled libraries the walk never sees. Version-less dependencies now
pass the platform filter before the reconciliation records them, so a
platform-excluded entry no longer draws a spurious drop warning.

A converted library whose matched files all fall through the source
suffix map warns instead of silently producing an empty archive, and
unhonored precompiled/ldflags properties fields warn by library name.
The ar rspfile parser undoes ninja's POSIX inner-quote escape and the
module docstring records the one-object-per-line contract. The
includeDir comment now states that warn-and-drop is intended.
2026-08-22 12:08:46 -05:00
J. Nick Koston b002a37987 Fail fast on empty compile databases and unsupported analyze-memory toolchains; degrade a missing size tool
ninja -t compdb exits 0 with an empty list when the rule names drift, so
the compile database is now parsed and an empty result fails the build
and drops the stale file. analyze-memory refuses an unsupported
toolchain before paying for the compile. A missing size binary warns
instead of discarding an already-linked build, _parse_app_size returns
explicitly from its not-found branch, and the CI cache action asserts
the caller's install prefix matches the cached path. The esp8266
run_compile dispatch hook and copy_files early-return gain direct
tests.
2026-08-22 12:06:38 -05:00
J. Nick Koston 583f47034f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 12:02:36 -05:00
J. Nick Koston 10a22d7d74 Quote an overridden ldscript name on the link line; note the deliberate board-derived --flash_size
The -T script name was the one user-controlled token on the link line
that skipped shell_token, so a space or dollar sign in a
board_build.ldscript override corrupted the emitted linkflags. The
elf2bin comment now records that --flash_size deliberately stays
board-derived, matching PlatformIO (which reads upload.maximum_size,
not the ldscript).
2026-08-22 12:02:33 -05:00
J. Nick Koston 905b056756 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
2026-08-22 12:01:44 -05:00
J. Nick Koston dc1bbac385 Harden the build spec: content-hashed ld cache, strict f_cpu, loud diagnostics
The linker-script stamp now records the sha256 of the written content, so
an externally edited or truncated cached script regenerates instead of
passing a SECTIONS substring probe, and a non-UTF-8 cached script is
overwritten by the regeneration instead of aborting it. The cached
preprocessor diagnostic re-emit no longer swallows its own read failure.

board_build.f_cpu is validated (digits with an optional L) before landing
unquoted on the compile line, _pio_option rejects empty and blank values
instead of silently reverting to the default, and user MMU define bodies
re-quote through shell_token like every other user token. The plain-form
linker denylist is a named constant the _project_flags docstring points
at, so the two cannot drift.
2026-08-22 12:01:08 -05:00
J. Nick Koston b597a4f02f Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 11:55:59 -05:00
J. Nick Koston 0c64ce7a8c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 11:55:59 -05:00
J. Nick Koston ba521acdab Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 11:55:59 -05:00
J. Nick Koston 9676e0c0f0 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 11:55:58 -05:00
J. Nick Koston cedecf1f83 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 11:55:58 -05:00
J. Nick Koston e7d3c1b92b Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-22 11:55:58 -05:00
J. Nick Koston f28be76c84 Fix comment drift: conditional cache refresh, future-tense generator consumer 2026-08-22 11:55:15 -05:00
J. Nick Koston fcc7bb8c44 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 11:49:37 -05:00
J. Nick Koston 3e646470ef Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 11:49:36 -05:00
J. Nick Koston ec9200912d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 11:49:36 -05:00
J. Nick Koston 3242196f9c Validate shorthand dependencies, honor lib_ignore for version-less deps, warn on non-platform component drops
The dict-shorthand dependency form now runs the same name validation as
the list form, so an empty key or a spec overriding name with a
non-string warns instead of raising a bare TypeError from the key
builder. A lib_ignore'd version-less dependency is deliberately excluded
and no longer draws the reconciliation warning. The walk's
component-level InvalidLibrary handler mirrors dependency_is_usable:
cross-platform skips stay at debug, any other cause warns. A malformed
libArchive/dot_a_linkage value now fails naming the library like the
sibling build fields, and the suffix map gains SCons's case-sensitive .C
and .C++ so those sources compile as C++ instead of silently dropping
out of the archive.
2026-08-22 11:49:25 -05:00
J. Nick Koston 4866ef97f0 Trim comment essays and hoist function-local test imports 2026-08-22 11:46:49 -05:00
J. Nick Koston 7e675233c6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 11:44:16 -05:00
J. Nick Koston 512a31b3fc Trim comment essays and hoist function-local test imports 2026-08-22 11:44:09 -05:00
J. Nick Koston 3134239d52 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 11:43:02 -05:00
J. Nick Koston 67544598c5 Trim comment essays 2026-08-22 11:42:55 -05:00
J. Nick Koston 351eb9209f Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 11:42:02 -05:00
J. Nick Koston c7a96f77d2 Trim comment essays and hoist function-local test imports 2026-08-22 11:41:59 -05:00
J. Nick Koston fc8a48d70b Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/espidf/component.py
2026-08-22 11:40:11 -05:00
J. Nick Koston cdde9dd230 Trim comment essays and hoist function-local test imports 2026-08-22 11:39:54 -05:00
J. Nick Koston 935db6a63c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-22 11:38:49 -05:00
J. Nick Koston 90b29e231d Trim comment essays and hoist function-local test imports 2026-08-22 11:38:46 -05:00
J. Nick Koston 315abf21f8 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-22 11:37:21 -05:00
J. Nick Koston 24e5b1800f Trim comment essays and hoist function-local test imports 2026-08-22 11:37:16 -05:00
J. Nick Koston 11eca53a18 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-22 11:35:41 -05:00
J. Nick Koston f08e06f574 Trim comment essays and hoist function-local test imports 2026-08-22 11:35:35 -05:00
J. Nick Koston 27f4db8458 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-22 11:34:57 -05:00
J. Nick Koston e99e0cc8b8 Trim comment essays and hoist function-local test imports 2026-08-22 11:34:32 -05:00
J. Nick Koston 9304c74de5 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 11:24:58 -05:00
J. Nick Koston 538d52c6bc Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 11:24:58 -05:00
J. Nick Koston d1db0cb63e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 11:24:58 -05:00
J. Nick Koston 3b2fc9f59a Close the owner-qualified drop gap and the duplicate-archive gap in the library backend
An owner-qualified version-less dependency was skipped by both the
arduino backend (owner set) and the reconciliation (provides() knew the
short name), so nothing logged the drop; provides() now only satisfies
owner-less names, mirroring the walk's backend-provided guard. A dict
dependency entry with no name at all now warns in the normalizer like
any other malformed entry.

Bundled dependency additions are deferred until conversion finishes and
skipped when a converted library's manifest already provides the name,
so a name that is both bundled and registry-resolved cannot build twice.
External short names come from the request spec (custom Name=url form
included) instead of the URL tail. The empty-bundled-library probe now
walks the whole library tree against a shared header-suffix constant,
and the dead versioned-dependency branch is folded into the surviving
check.
2026-08-22 11:24:49 -05:00
J. Nick Koston 266f67ef13 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 11:04:48 -05:00
J. Nick Koston ee218bdc7d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 11:04:47 -05:00
J. Nick Koston 5dea42d28a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 11:04:47 -05:00
J. Nick Koston 57e738adf8 Simplify the library backend: share the dependency filter, drop the request-key drop diff, dedupe test scaffolding
Validate manifest shape once in the converter (every backend dereferences
data/build), share the InvalidLibrary filter as dependency_is_usable(),
and let the walk's reconciliation own version-less drop reporting so the
arduino backend's request-key diff, owner-no-version warning, and
node_key plumbing all go away. One memoized _provided() predicate now
answers bundled-name checks at all three sites. Tests gain shared
scaffold helpers and lose the assertions that pinned deleted messages.
2026-08-22 11:04:35 -05:00
J. Nick Koston 70b8573110 Move version-less drop reconciliation into the walk, harden the name guards
The shared walk now defers every version-less skip and reconciles after
emit against the final resolution set (request keys, resolved manifest
names, and backend.provides(name) per name), so drop visibility is
correct for every backend by construction instead of by a comment-level
contract, and the arduino backend's duplicate pending_drops pass and its
short-name suppression heuristics are deleted. The provides lambda
applies _is_safe_library_name so an unsafe manifest name is simply not
provided, and the guard also rejects drive-colon names that would
escape the tree on Windows.
2026-08-22 10:46:50 -05:00
J. Nick Koston 772fb65675 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 10:03:46 -05:00
J. Nick Koston 116f7479a3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 10:03:46 -05:00
J. Nick Koston 40c28c3861 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 10:03:45 -05:00
J. Nick Koston 735d4076c1 Keep the top-level suppression total and honest
The check guards URL-ish names before _node_key (a malformed entry
belongs to the drop warning, not a RuntimeError) and matches against
top_level_keys so the message says exactly what it verifies; a
transitive-only node can still fail compatibility later and must not
suppress the drop report.
2026-08-22 10:03:43 -05:00
J. Nick Koston 00549813ab Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 09:41:49 -05:00
J. Nick Koston c2e920d769 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 09:41:49 -05:00
J. Nick Koston 69ab07ec41 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 09:41:49 -05:00
J. Nick Koston a48fbd1cd1 Suppress the top-level-requested false positive, guard names once, fail empty bundled libraries
The walk's version-less warning stays quiet for a name the config also
requests top-level, and the provides-backend debug level carries the
ownership rationale (the arduino backend defers drops and suppresses
walk-resolved names this layer cannot know yet). _is_safe_library_name
guards both the top-level bundled check and manifest dependencies, so a
YAML libraries entry of '.' or a backslash name cannot join under the
framework tree. The drop suppression strips only the sanitized owner
prefix, keeping a library's own double underscores. An empty bundled
directory raises naming the fix instead of warning into an unlinkable
build, and the second real-converter test pins ESPHOME_DATA_DIR.
2026-08-22 09:41:35 -05:00
J. Nick Koston ccce5e9ab2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 09:30:02 -05:00
J. Nick Koston 3b9a026fd4 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 09:30:02 -05:00
J. Nick Koston a4d99a8ee9 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 09:30:02 -05:00
J. Nick Koston e47ec9acad Cover the routine version-less skip through the real walk 2026-08-22 09:29:49 -05:00
J. Nick Koston 685409cf83 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 09:21:11 -05:00
J. Nick Koston bff4b7d870 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 09:21:11 -05:00
J. Nick Koston 965557ee11 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 09:21:10 -05:00
J. Nick Koston 8e6af6aa8c Name the manifest in every dependency diagnostic, warn where no backend can recover
normalize_dependencies' parameter is manifest_name (the dict branch
already binds owner to a package owner), and the arduino call site
passes the library's name so its unrecognized-entry warning stops
saying 'of manifest'. A version-less dependency warns when the backend
declares no provides tree (espidf/zephyr/nrf52 have no post-emit
pickup), and the shared walk mirrors the typed IncompatiblePlatform
branch: routine platform skips stay at debug, any other InvalidLibrary
cause warns naming the component. The two real-converter tests pin
ESPHOME_DATA_DIR to tmp_path so an ambient data dir cannot leak in.
2026-08-22 09:20:57 -05:00
J. Nick Koston 7c91407835 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 00:48:41 -05:00
J. Nick Koston 33c6b3161b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 00:48:41 -05:00
J. Nick Koston 2cedb3d82b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 00:48:41 -05:00
J. Nick Koston 9bb899d8df Never shred a string dependency list, defer and de-duplicate drop warnings
A plain-string dependencies value comma-splits into names instead of
iterating into one-character libraries; entries that normalize to
nothing warn naming the manifest, and the walk's version-less skip logs
at debug for every backend. The not-bundled warning is deferred until
after the walk and stays quiet for names resolved transitively, so a
false skipping message cannot teach users to ignore the real one. An
explicitly requested bundled library that resolves to no sources and no
headers warns that the install may be incomplete.
2026-08-22 00:48:30 -05:00
J. Nick Koston 76a80bd346 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-22 00:18:46 -05:00
J. Nick Koston 7ab66de38b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-22 00:18:46 -05:00
J. Nick Koston 0bd66b8e9b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-22 00:18:46 -05:00
J. Nick Koston 35c77165ca Surface every dependency-drop path the walk can take
The converted path warns for a properties-only depends= spelling (the
walk reads the JSON key). A dependency name is validated before
becoming a path component: non-strings and separator names are
malformed entries, never joined (apply_extra_script already guards the
same shape). normalize_dependencies coerces PIO's bare string-list form
to name dicts instead of dropping it before every visibility warning. A
non-* version pin discarded for a backend-provided bundled copy warns
naming the substitution. The -I global-include promotion and the
start-group link-order contract are documented.
2026-08-22 00:18:35 -05:00
J. Nick Koston 0f885b4037 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 21:27:59 -05:00
J. Nick Koston 09518f4032 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 21:27:59 -05:00
J. Nick Koston 7732b688f5 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 21:27:59 -05:00
J. Nick Koston 44b14d8655 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 21:27:59 -05:00
J. Nick Koston 4eb31c45da Isolate the preresolved-ccache test from ambient CCACHE_DIR, future-tense the sentinel comment 2026-08-21 21:27:49 -05:00
J. Nick Koston 8b21fa620d Cover the pre-resolved ccache branch of get_idedata 2026-08-21 21:20:58 -05:00
J. Nick Koston 116b4ce444 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 21:11:22 -05:00
J. Nick Koston 91cf9be5eb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 21:11:21 -05:00
J. Nick Koston 2959fb6e7d Resolve the test's gcc path through toolchain_tool so Windows stats the .exe 2026-08-21 21:11:20 -05:00
J. Nick Koston eecdf3e68d Drop the components-graph memo; it defeats the tested disk-cache semantics
The in-process cache served a stale graph across mtime and version
changes, which the script test suite pins; the saved re-parse was tens
of milliseconds.
2026-08-21 21:11:11 -05:00
J. Nick Koston c0a605c1b9 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 21:01:48 -05:00
J. Nick Koston 227522364a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 21:01:47 -05:00
J. Nick Koston 4bea2dd058 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 21:01:47 -05:00
J. Nick Koston a9994c6895 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 21:01:47 -05:00
J. Nick Koston fab8af6c88 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 21:01:47 -05:00
J. Nick Koston db0e52a36b Cover shell_token's Windows branch on the coverage-uploading runner 2026-08-21 21:01:37 -05:00
J. Nick Koston 9fe9d8da1b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:56:38 -05:00
J. Nick Koston 897713cbcb Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 20:56:38 -05:00
J. Nick Koston a05a392fdd Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:56:37 -05:00
J. Nick Koston 6a963ba794 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 20:56:37 -05:00
J. Nick Koston a029338f3d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:56:37 -05:00
J. Nick Koston cbf9e0ab14 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 20:56:37 -05:00
J. Nick Koston a527b21761 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-21 20:56:36 -05:00
J. Nick Koston 4d63564cdd Phrase the board-table regen comment imperatively 2026-08-21 20:56:27 -05:00
J. Nick Koston 8b9f5503df Drop the now-inlined pio_options module 2026-08-21 20:55:58 -05:00
J. Nick Koston 17f718e8c9 Simplify the native dispatch and CI cache wiring
A cache-arduino8266 composite action mirrors cache-esp-idf (one key
resolver, dev-writes/PR-restores) and both jobs pin
ESPHOME_ARDUINO8266_PREFIX so YAML and Python agree on the path by
construction. esp32 provides the native_toolchain_module hook, so the
shared dispatcher never names a backend and the unclaimed-native raise
loses its esp-idf carve-out; the esp8266 decode and run_compile hooks
resolve through the same seam. run_compile resolves ccache once and
threads it to the generator, env, and idedata; the compdb rule names
follow the shared kinds; the pio-options warner inlines into the driver
and derives its consumed set from the core routing constant; the
per-toolchain CI narrowing shares one body; create_components_graph is
memoized per run; the decode rate-limit drops its math sentinel.
2026-08-21 20:55:27 -05:00
J. Nick Koston 39f11815ed Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 20:55:19 -05:00
J. Nick Koston 42e255c1e5 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:55:19 -05:00
J. Nick Koston efad21d335 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:55:19 -05:00
J. Nick Koston 16bc83032d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:55:19 -05:00
J. Nick Koston 012b571a2e Make the ccache sentinel public; sibling modules pass it as a default 2026-08-21 20:55:07 -05:00
J. Nick Koston ff0298c66a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 20:51:57 -05:00
J. Nick Koston a1d59049b4 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:51:57 -05:00
J. Nick Koston c838d11bf4 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:51:57 -05:00
J. Nick Koston 814109df47 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:51:57 -05:00
J. Nick Koston 4a16365f13 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 20:51:56 -05:00
J. Nick Koston 587873a2da Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 20:51:56 -05:00
J. Nick Koston 80a4178f05 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:49:32 -05:00
J. Nick Koston 0973044214 Strip the python path for cmd.exe, name rules by kind, take the resolved install
The build.ninja python variable goes through strip_win_long_path_prefix
like every other emitted binary path (the NSIS launcher's extended
prefix cannot be spawned by cmd.exe). Compile rules are named by the
shared source kinds directly, retiring the identity translation table
and its drift test. write_project takes the caller's resolved ccache,
get_flash_ld_path reads the InstalledPaths the ninja file linked
against instead of re-resolving the version, the board backstop checks
the one table it indexes with an honest comment, and cc/cxx/ar paths go
through the shared toolchain_tool accessor (gaining the Windows
suffix).
2026-08-21 20:49:30 -05:00
J. Nick Koston d628bc3aae Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 20:47:42 -05:00
J. Nick Koston e5ad855337 Use the shared tool accessor for gcc, drop dead dataclass defaults, add a resolve test helper
toolchain_tool owns the bin path and Windows suffix now; _BuildConfig's
knob and MMU fields are required since the only constructor always
passes both; the tests' set-flags-then-resolve idiom collapses into one
_resolve helper (12 sites).
2026-08-21 20:47:17 -05:00
J. Nick Koston aad89cd939 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:46:18 -05:00
J. Nick Koston 67f6812f78 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:46:18 -05:00
J. Nick Koston 4101ad4fb1 One owner for the toolchain tool layout, thread a pre-resolved ccache
toolchain_tool carries the bin/xtensa-lx106-elf-<name> pattern and the
Windows suffix that four call sites previously spelled out (only one of
which handled the suffix). ccache_env and get_build_env accept the
already-resolved ccache path so run_compile can resolve once instead of
paying the PATH scan and runnability probe three times per build.
2026-08-21 20:46:10 -05:00
J. Nick Koston 048025e9dd Form the local-library URL with as_uri so the test passes on Windows 2026-08-21 20:44:49 -05:00
J. Nick Koston e9d6132c61 Name the honored native-arduino pio options once
NATIVE_ARDUINO_PIO_OPTIONS is the single list the routing reads; the
backend's ignored-option warning consumes it too, so honoring a new key
is one edit instead of two synchronized ones.
2026-08-21 20:43:43 -05:00
J. Nick Koston 9268f52b9e Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:38:33 -05:00
J. Nick Koston df91523ce3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 20:38:33 -05:00
J. Nick Koston e779df14cb Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:38:32 -05:00
J. Nick Koston 8ad1ed98b7 Skip backend-provided dependencies in the graph walk, validate manifests before extra scripts
The dict-shorthand bundled preference ran after convert_libraries had
already resolved the dependency through the registry, so a real
{"Wire": "*"} manifest still fetched or failed on a registry Wire (the
mocked test hid it). LibraryBackend gains an optional provides hook the
walk consults for owner-less dependencies; the arduino backend answers
from the framework tree and the bundled copy is added after emit. A
real-converter test with a local library pins that the registry is
never touched. _emit also validates the manifest shape by name before
apply_extra_script dereferences it.
2026-08-21 20:38:23 -05:00
J. Nick Koston f2a878cb25 Stop warning about the now-honored f_cpu and ldscript overrides 2026-08-21 20:31:12 -05:00
J. Nick Koston c9a40e550c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:30:32 -05:00
J. Nick Koston 5474ba2ca1 Honor board_build.ldscript for the native flash linker script
Published configs override it to reserve a filesystem region or correct
a board's assumed flash size; the routed value replaces the BOARDS
default, and a path is rejected since the name resolves via -L.
2026-08-21 20:30:30 -05:00
J. Nick Koston accfd12199 Honor board_build.f_cpu on the native compile line
The routed override (published configs pin 160000000L for
timing-sensitive integrations) reaches -DF_CPU via a small _pio_option
reader; the default stays the audited 80 MHz all 45 boards ship.
2026-08-21 20:28:27 -05:00
J. Nick Koston 7298eed5b3 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 20:27:43 -05:00
J. Nick Koston 78a1e88915 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 20:27:43 -05:00
J. Nick Koston b87875881e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:27:43 -05:00
J. Nick Koston e97388ce00 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:27:43 -05:00
J. Nick Koston d8c02221cc Route board_build.ldscript through to the native ESP8266 generator too
Published configs override it to reserve a filesystem region
(SmartIntercom's eagle.flash.4m2m.ld) or to correct a board's assumed
flash size (2 MB ESP8285 plugs pinning eagle.flash.2m.ld); dropping it
changes the flash layout under them.
2026-08-21 20:27:33 -05:00
J. Nick Koston 8cefacd7b6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 20:25:33 -05:00
J. Nick Koston 76d8c9eb46 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 20:25:32 -05:00
J. Nick Koston a703acf85f Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 20:25:32 -05:00
J. Nick Koston 7beda110d4 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 20:25:32 -05:00
J. Nick Koston 7fb18f395f Honor board_build.f_cpu under the native ESP8266 Arduino toolchain
Dropping it was a real regression: many published ESP8266 configs pin
board_build.f_cpu: 160000000L for timing-sensitive integrations
(MHI-AC-Ctrl documents the 160 MHz requirement in its example), and the
warn-and-drop left those devices at 80 MHz. The option now routes into
CORE.platformio_options under toolchain: arduino for the generator to
consume; other native toolchains keep the warning.
2026-08-21 20:25:23 -05:00
J. Nick Koston 6070941771 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 20:22:05 -05:00
J. Nick Koston d78083f9f2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 20:22:05 -05:00
J. Nick Koston 44b64e0963 Note why F_CPU is hardcoded, widen the plain linker-flag denylist
F_CPU gets the same drift-audit note as _MMU_DEFAULT: upstream reads it
from the board manifest, and all 45 supported boards ship 80000000L.
The plain-form refusal also covers -e, -s, -static, and -nostartfiles,
which gcc accepts inertly on a -c line.
2026-08-21 20:21:57 -05:00
J. Nick Koston dc0fddd349 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 19:59:57 -05:00
J. Nick Koston 44db267a2c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 19:59:54 -05:00
J. Nick Koston df1aa5ff61 Make the lex-once contract structural, stamp the compiler, guard bare -I/-D
tokens is a required parameter on _flag_defines and _project_flags now,
so the per-consumer re-lex the shared lexer was meant to end cannot
come back. The cache stamp covers the gcc binary's size and mtime via
a shared _stat_sig (an in-place toolchain re-extraction regenerates
the script like a header edit). A bare -I or -D from an empty argument
is warned and skipped instead of letting gcc eat the next flag.
_defines_flags documents that its tokens carry shell-level escaping and
must be emitted unquoted, and _MMU_DEFAULT notes why the board-manifest
values are hardcoded.
2026-08-21 19:59:26 -05:00
J. Nick Koston 26ea560139 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 19:24:21 -05:00
J. Nick Koston 4cec2e119c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 19:24:20 -05:00
J. Nick Koston 7c4dfe8c08 Best-effort stderr-note re-emit, name the unreadable-header cause, state the quoting contract
The cached-diagnostic read follows the same regenerate-never-abort rule
as the other cache reads (a damaged note must not fail an incremental
build). The unreadable-header path warns naming the header and the
clean-all fix instead of leaving an inexplicably uncached build at
debug level. _project_flags' docstring states which return values are
pre-quoted and which the caller owns.
2026-08-21 19:24:10 -05:00
J. Nick Koston f3395afae1 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 18:56:03 -05:00
J. Nick Koston 69f558d83d Pin the board-table equality, note the flash_freq audit
write_project rejects a board missing from either table, so a new test
asserts the two stay exactly equal (the subset check is how d1_wroom_02
went missing). The hardcoded --flash_freq 40 carries the audit note:
all 45 supported boards ship 40 MHz, and a platform bump adding one
that does not must revisit it.
2026-08-21 18:55:52 -05:00
J. Nick Koston 6b56def2bf Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 18:55:40 -05:00
J. Nick Koston ce5ccb4294 Name every ld-generation failure, refuse inert linker flags, reuse the shared lexer
Both testing-mode segment patches get the RuntimeError-to-EsphomeError
wrap the ratetable surgery already had. Plain-form -T/-Xlinker/-u flags
raise naming the -Wl, form instead of warning into an inert -c compile
line. _lexed_build_flags and _unflag_tokens go through the shared
lex_build_flags so a future lexing fix cannot miss this path. The MMU
conflict message names dropping the variant knob when MMU_CUSTOM is
already set. An unreadable (not absent) header forces a cache miss
every run instead of pinning the stamp to a constant, and preprocessor
warnings persist beside the stamp and re-emit on cache hits. The drift
docstring states what the tests actually pin.
2026-08-21 18:54:19 -05:00
J. Nick Koston f451de062a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 17:45:05 -05:00
J. Nick Koston 923e293537 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 17:45:05 -05:00
J. Nick Koston f92386b3cc Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 17:45:04 -05:00
J. Nick Koston c1a7c87a64 Cover the non-dict bundled-manifest branch 2026-08-21 17:44:57 -05:00
J. Nick Koston 88e6471a4b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 17:38:34 -05:00
J. Nick Koston 9fd323e7d9 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 17:38:33 -05:00
J. Nick Koston 4e830241d0 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 17:38:33 -05:00
J. Nick Koston d96ddf3612 Catch the depends= spelling, warn on bundled extraScripts, trust top-level requests
The bundled-dependency visibility warning also reads the
library.properties depends= key the shared parser returns raw, since
properties is the format bundled libraries actually ship. A bundled
manifest declaring an extraScript warns that it never runs (a new
Known-deviations entry). A version-less manifest dependency the config
separately requests as a top-level library is already in the build, so
the skipping warning no longer fires for it and cannot teach users to
ignore the real drop.
2026-08-21 17:38:25 -05:00
J. Nick Koston daea0cc9f3 Warn on missing decode tools on both toolchains, fail the CI key resolver loudly
The PlatformIO branch of _decode_pc now routes through the same
rate-limited warning as the native one; raw undecoded crash addresses
with no stated reason were undiagnosable at default log level. The CI
cache key uses the assignment form so errexit catches a resolver
failure instead of echo swallowing it into a degenerate key, with a
non-empty check, and the cache comments stop claiming a ccache store
the seed job never populates (it saves before any compile runs).
2026-08-21 17:26:11 -05:00
J. Nick Koston cb409e276a Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 17:19:09 -05:00
J. Nick Koston d0a3392c46 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 17:19:09 -05:00
J. Nick Koston 978d7fc2e7 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 17:19:09 -05:00
J. Nick Koston e18852e084 Fail on dropped requests, guard the last manifest fields, parse dot_a_linkage strictly
A top-level library the converter dropped always makes the firmware
wrong, so resolve_libraries raises naming the missing requests instead
of warning toward link errors, and a resolved component without its
node_key fails as a converter bug rather than silently substituting the
mismatched canonical name. includeDir and srcFilter join srcDir and
flags in raising a named error on malformed values, and dot_a_linkage
parses through the same strict table as libArchive so a typo warns and
keeps the archive default instead of flipping link semantics.
2026-08-21 17:19:01 -05:00
J. Nick Koston 27b80f895b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 17:04:13 -05:00
J. Nick Koston e2cc4e825f Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 17:04:12 -05:00
J. Nick Koston 496d705dc7 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 17:04:12 -05:00
J. Nick Koston 1f868d22fb Expose request_key as the public pair of ConvertedLibrary.node_key
The arduino backend consumed the private _node_key across packages to
reconstruct the request-side key; the thin public wrapper keeps both
sides of the contract on the same API surface.
2026-08-21 17:04:03 -05:00
J. Nick Koston 3e56619cd6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 16:52:50 -05:00
J. Nick Koston 84d98a3593 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 16:52:50 -05:00
J. Nick Koston bf3972cbf6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 16:52:50 -05:00
J. Nick Koston 2ecf7af416 Name malformed manifests, diff drop-warnings by node key, surface bundled deps
A non-dict manifest or build section raises an EsphomeError naming the
library instead of an AttributeError. ConvertedLibrary remembers the
request-side node key it resolved from, so the converter-drop warning
diffs requests against those keys; a bare name resolving to a canonical
owner__pkg is no longer falsely listed missing. A bundled library whose
manifest declares dependencies warns that the walk never runs for it (a
no-op on the ESP8266 core, not on every core this module serves).
2026-08-21 16:52:32 -05:00
J. Nick Koston 7a99e65853 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 16:07:41 -05:00
J. Nick Koston 5622a7b851 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 16:07:40 -05:00
J. Nick Koston 659211b8bd Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 16:07:40 -05:00
J. Nick Koston 91a4eb0f57 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 16:07:40 -05:00
J. Nick Koston 97ed253c38 Say the floor's config-validation guard is future wiring, not present
Nothing at this commit enforces MIN_FRAMEWORK_VERSION during
validation; the native backend's validator arrives with the wiring PR.
The comment no longer invites skipping it.
2026-08-21 16:07:30 -05:00
J. Nick Koston 0127b483b0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 15:34:01 -05:00
J. Nick Koston 114302b518 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 15:34:01 -05:00
J. Nick Koston e2d0ebbd6e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 15:34:01 -05:00
J. Nick Koston be2395da66 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 15:34:00 -05:00
J. Nick Koston cbf1241401 Resolve the ccache path on every call, matching the espidf backend
functools.cache froze the ESPHOME_CCACHE_ENABLE/PATH decision for the
process lifetime, which a long-lived host like device-builder never
restarts, and forced a cache_clear fixture in the tests. The docstring
and test now pin the uncached delegation.
2026-08-21 15:33:51 -05:00
J. Nick Koston 98f574c251 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 15:19:11 -05:00
J. Nick Koston 568885f80d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 15:19:11 -05:00
J. Nick Koston 17a251d062 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 15:19:10 -05:00
J. Nick Koston ce87ca2e11 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 15:19:10 -05:00
J. Nick Koston 33aea420ac Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 15:19:10 -05:00
J. Nick Koston e3d29e9fff Name a non-list registry system field instead of a TypeError
file["system"] normalized None and str but let an int or dict fall
through to the in test, where an int raises TypeError and a dict
becomes a key test; both now raise the same Unexpected-response error
as the other shape guards.
2026-08-21 15:18:54 -05:00
J. Nick Koston dbae5246e6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 14:50:47 -05:00
J. Nick Koston 2fba991b51 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 14:50:47 -05:00
J. Nick Koston 92356804c6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 14:50:47 -05:00
J. Nick Koston 03bf037cb8 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 14:50:47 -05:00
J. Nick Koston 4dc2d34399 State the encoder's real registry parity and why the 3.1.1 floor exists
The docstring claimed exact registry names for every core above 2.6.2;
2.6.3, 3.0.0 and 3.0.1 ship with non-zero trailing components the
formula cannot produce. Name them, say which callers are safe (the ~
range on the PlatformIO path, the floored check_and_install), and
credit the floor with covering 3.0.0/3.0.1 as well as the absent 3.1.0.
2026-08-21 14:50:36 -05:00
J. Nick Koston b131f51788 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 14:32:37 -05:00
J. Nick Koston ccaa2a8f0d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 14:32:37 -05:00
J. Nick Koston a2b28a8f8d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 14:32:37 -05:00
J. Nick Koston e9f8233f67 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 14:32:37 -05:00
J. Nick Koston c07a5a8da4 Match the encoder's lower bound to the PlatformIO era guard, drop the unused logger
<= 2.6.2 instead of < 2.6.3: a 2.6.2 pre-release sorts above 2.6.2 and
belongs to the package-major-3 encoding, so the helper now describes
the same set as _format_framework_arduino_version and a 2.6.2-b1 pin
formats as it does on dev. The module never logged, so its _LOGGER and
logging import go.
2026-08-21 14:32:27 -05:00
J. Nick Koston 0097ce892c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 14:12:34 -05:00
J. Nick Koston a3b2954321 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 14:12:33 -05:00
J. Nick Koston d07ed5b397 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 14:12:33 -05:00
J. Nick Koston b4514e5af2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 14:12:33 -05:00
J. Nick Koston 93a768531d Anchor the 4.x error to the version key, bound the encoder, build PATH without empty entries
cv.Invalid now carries path=[CONF_VERSION] so the rejection lands on
the framework version line the comment promised, matching the esp32
convention. framework_package_version raises for cores before 2.6.3
instead of encoding them wrongly for a caller that skipped the
PlatformIO path's era guard. get_build_env joins PATH from filtered
parts so an absent PATH cannot leave a trailing separator that the
shell reads as the current directory.
2026-08-21 14:12:20 -05:00
J. Nick Koston 9fbc996d52 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 13:33:19 -05:00
J. Nick Koston 046c7e5eb0 Lex build flags once in write_project, warn on unflags that match nothing
The pre-lexed tokens feed both _flag_defines and _project_flags so a
malformed entry warns once per generation. An unflag that hits nothing
in the user flags or any framework set (a typo, or -DUSE_FOO against
-DUSE_FOO=1) is named instead of silently leaving the flag in force.
2026-08-21 13:33:11 -05:00
J. Nick Koston c0cd64cd76 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 13:32:21 -05:00
J. Nick Koston 7c2254d8ee Refuse knob-plus-raw define splits, lex build flags once, harden the ld cache
A raw MMU_* define alongside a PIO_FRAMEWORK_ARDUINO_MMU_* knob, or a
raw TCP_MSS/LWIP_* alongside the lwIP knobs, would win the compile line
while the linker script or prebuilt library keeps the knob's values;
both now raise like the no-knob case. _MMU_VARIANTS holds tuples and the
resolved config gets a copy, so nothing aliases the module table.
_lexed_build_flags lexes once and both consumers accept the tokens, so
a malformed entry warns once per build. The linker-script stamp covers
the header's size and mtime, an unreadable or non-UTF-8 cache
regenerates instead of aborting, plain-form linker flags warn that they
are not routed to the link line, and a moved rate-table anchor surfaces
as a named build error.
2026-08-21 13:32:12 -05:00
J. Nick Koston c92b3cc49a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 13:13:16 -05:00
J. Nick Koston 4898dc0800 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 13:13:15 -05:00
J. Nick Koston e3cf2407ca Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 13:13:15 -05:00
J. Nick Koston 82d1ffebf2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 13:13:15 -05:00
J. Nick Koston bfeb27cd2a Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 13:13:15 -05:00
J. Nick Koston 45cbe0aa4b Parse IDF_CCACHE_ENABLE strictly through the shared helper, fix the ccache docstrings
parse_enable_env carries the 1/true/yes/on and 0/false/no/off table for
both knobs, so IDF_CCACHE_ENABLE=off disables instead of reading as
truthy and suppressing the shared opt-out. The ccache module docstring
and the ESP-IDF _ccache_env docstring now describe the precedence this
PR actually ships, and the probe test duplicated by the helper move is
dropped from the PlatformIO toolchain tests.
2026-08-21 13:12:57 -05:00
J. Nick Koston c3c27dc744 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 13:07:04 -05:00
J. Nick Koston 9153f03c83 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 13:07:03 -05:00
J. Nick Koston 84de74663c Cover the testing-mode flash-ld OSError guard 2026-08-21 13:06:33 -05:00
J. Nick Koston 6974a67626 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 12:57:46 -05:00
J. Nick Koston 937c69e420 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 12:57:45 -05:00
J. Nick Koston e9409f46db Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 12:57:45 -05:00
J. Nick Koston 211889cfb6 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 12:57:45 -05:00
J. Nick Koston debfff005b Check the elf2bin inputs at generation, quote cxx flags, add d1_wroom_02 to BOARDS
elf2bin.py and eboot.elf join the existence checks so a half-extracted
package fails by name before the compile instead of at the
second-to-last edge. get_project_cxx_compile_flags() values go through
_shell_token like every other flag source. d1_wroom_02 (2 MB, in
ESP8266_BOARD_BUILD and buildable under PlatformIO) joins BOARDS so the
native board guard stops rejecting it, and the guard comment states
what config validation actually checks.
2026-08-21 12:57:36 -05:00
J. Nick Koston 523150a4c9 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 12:55:51 -05:00
J. Nick Koston 784cf6819f Refuse inconsistent memory-layout configs, validate the cached linker script
Unknown or conflicting VTABLES_IN_* defines raise instead of warning
and picking arbitrarily (a typo previously won the sorted pick and died
in the SDK header's #error). Custom MMU sizes without the CUSTOM knob
raise too: PlatformIO warns but its defaults win the compile line,
while here the user's tokens would win and compile against a layout the
linker script does not implement. The cached linker script is re-checked
for its SECTIONS block so a truncated file regenerates, the
testing-mode flash-ld read gets the same OSError guard as the gcc
spawn, the ParseFlags docstring states its actual coverage, and the ld
test mocks are quiet so the clean path asserts no warnings.
2026-08-21 12:55:23 -05:00
J. Nick Koston 4af70c3a4d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 12:53:46 -05:00
J. Nick Koston 0cb307aea5 Type the platform rejection, prefer bundled deps, parse manifests strictly
check_library_data's platform filter raises IncompatiblePlatform (an
InvalidLibrary subclass) so the arduino backend branches on the type
instead of substring-matching the message. The {"Wire": "*"} dict
shorthand resolves to the bundled library like PIO's
process_dependencies instead of a registry lookup. libArchive parses
booleans and true/false strings and warns on anything else (bool(str)
made "false" archive). A declared-but-falsy srcDir raises instead of
silently probing. The converter-drop warning names the missing requests,
and the bundled-walk comment states what PIO actually does.
2026-08-21 12:53:39 -05:00
J. Nick Koston 1f1cab9c37 Anchor the 4.x rejection to the framework version line, isolate the ccache env test
The installer's EsphomeError becomes cv.Invalid at the config
validator, and test_ccache_env clears the ambient environment so a
developer's exported CCACHE_DIR cannot fail it.
2026-08-21 12:51:09 -05:00
J. Nick Koston 4936ec0de6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 12:28:19 -05:00
J. Nick Koston afe12061d2 Track the per-platform shell quoting in the emission drift tests
The asm -D/-I filter also strips a leading single quote now that POSIX
tokens are single-quoted.
2026-08-21 12:28:11 -05:00
J. Nick Koston 2d89ca3dd0 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-21 12:26:46 -05:00
J. Nick Koston a7febfbf05 Track the per-platform shell quoting in the requote drift test 2026-08-21 12:26:23 -05:00
J. Nick Koston 6d23a2c9e5 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 12:25:14 -05:00
J. Nick Koston f12cb4350a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 12:25:14 -05:00
J. Nick Koston 3e218e43cd Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 12:25:14 -05:00
J. Nick Koston e12795c285 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 12:25:14 -05:00
J. Nick Koston 85335de839 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 12:25:13 -05:00
J. Nick Koston 0f7cd3fada Single-quote POSIX shell tokens, share the tool probe, harden registry checks
shell_token now picks the quoting style per platform: single quotes on
POSIX (sh expands nothing inside them, so backslash runs, $VAR, and
backticks reach the compiler exactly as lexed, matching SCons's
no-shell spawn) and the CreateProcess argv rule on Windows. A test
round-trips every case through a real /bin/sh.

The ninja and ccache runnability probes collapse into one
tool_version_runs helper in framework_helpers. The registry names a
non-dict top-level payload like the inner guards, and the expect layout
check also runs on marker hits so a marked install that later lost
files fails by name. The ESP-IDF ccache gate defers to
resolve_ccache_path so ESPHOME_CCACHE_ENABLE=0 disables ccache there
too, with IDF_CCACHE_ENABLE still taking precedence.
2026-08-21 12:25:03 -05:00
J. Nick Koston c8722421b1 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 11:14:36 -05:00
J. Nick Koston 78a41161cb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 11:14:35 -05:00
J. Nick Koston 6093f3f1ce Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 11:14:35 -05:00
J. Nick Koston 01600d0abd Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 11:14:35 -05:00
J. Nick Koston 653f9e8f2a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 11:14:35 -05:00
J. Nick Koston 510f667bd1 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 11:14:35 -05:00
J. Nick Koston c93cf55967 Skip the cache refresh when the CLI toolchain differs from the compile's
Platforms normalize toolchain-sensitive keys differently (the esp32
board name, for one), so a config validated under a mismatching
--toolchain must not overwrite the cache while the sidecar keeps the
compile's toolchain. The guard lives in _refresh_sidecar where the old
sidecar is already loaded; legacy sidecars without the field are
unaffected.
2026-08-21 11:14:26 -05:00
J. Nick Koston 9ff0198865 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 09:58:45 -05:00
J. Nick Koston 9bd83e5d2d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 09:58:44 -05:00
J. Nick Koston 2ee1d89e04 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 09:58:44 -05:00
J. Nick Koston 3a2bd29c15 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 09:58:44 -05:00
J. Nick Koston f3f6fe8a7d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 09:58:44 -05:00
J. Nick Koston efe1b0e744 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 09:58:44 -05:00
J. Nick Koston 6cb446baf8 State what the cache refresh actually writes
The comment claimed the refresh's sidecar records the CLI toolchain;
_refresh_sidecar returns early when a compile-written sidecar exists,
so the compile's toolchain stands. Reword the comment and the test
docstring to match.
2026-08-21 09:58:32 -05:00
J. Nick Koston 0fa081cd80 Name malformed registry elements, parse ESPHOME_CCACHE_ENABLE strictly, require a package layout check
Registry version and file entries that are not dicts now raise the same
Unexpected-response error as the other shape guards instead of an
AttributeError traceback. install_package rejects an empty expect so
every install is layout-validated before the marker is written.
ESPHOME_CCACHE_ENABLE values outside 1/true/yes/on and 0/false/no/off
warn and are treated as unset instead of bool(str) flipping them to
enabled. The strip_win_long_path_prefix test moved next to the function
in test_framework_helpers, and a stale comment naming its old module is
fixed.
2026-08-21 09:58:16 -05:00
J. Nick Koston 503e3ca724 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-21 09:36:01 -05:00
J. Nick Koston b8ce65282e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 09:36:00 -05:00
J. Nick Koston 3a49955b45 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 09:36:00 -05:00
J. Nick Koston 5587e34a8c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 09:36:00 -05:00
J. Nick Koston 8fd8766167 Sandbox ESPHOME_ARDUINO8266_PREFIX in the writer test isolation fixture
The autouse fixture pinned the idf and sdk-nrf prefixes but not the new
arduino8266 one, so running the suite with that env var exported deleted
the pointed-to install. Also adds the clean_all removal test the other
two native installs already have.
2026-08-21 09:35:53 -05:00
J. Nick Koston e5cfb1bdac Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-21 01:06:06 -05:00
J. Nick Koston 225c62dbf1 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-21 01:05:51 -05:00
J. Nick Koston bb77ad01eb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-21 01:05:51 -05:00
J. Nick Koston 71c2381c60 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-21 01:05:51 -05:00
J. Nick Koston 2da961f560 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-21 01:05:51 -05:00
J. Nick Koston 0b0194cf41 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-21 01:05:51 -05:00
J. Nick Koston 8b9773c4bd Gate only the cache read on an explicit CLI toolchain, keep the refresh
The upload/logs cache split: an explicit --toolchain still skips the
read and runs the per-platform validators, but the freshly validated
config is saved again so a later plain run keeps the fast path (the
sidecar records the resolved toolchain). check_supported_toolchain is
module-private now since it has no caller outside config_validation,
and require_platformio_toolchain's docstring describes what actually
happens when another platform's toolchain is passed.
2026-08-21 01:05:38 -05:00
J. Nick Koston aae5538fd5 Gate uploads on a built firmware, refuse unclaimed native builds, seed the CI toolchain cache from dev
The upload path now checks CORE.firmware_bin exists before invoking
esptool and names the fix (compile first) instead of failing inside
esptool. compile_program raises when a native toolchain resolved but no
platform backend claimed the build rather than falling through to a
mis-configured PlatformIO project. The addr2line failure warning now
includes the exception so the cause is visible without debug logging.

CI: the native toolchain cache is restore-only on PRs and seeded by a
new dev-push job, mirroring seed-apt-cache; the key resolves the pinned
core and toolchain versions from code instead of hashing framework.py.
determine-jobs main() output tests now pin the esp8266_native pair.
2026-08-21 00:05:23 -05:00
J. Nick Koston 01923ff22a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 23:58:42 -05:00
J. Nick Koston 5a5a379444 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-20 23:58:18 -05:00
J. Nick Koston cd2ab6e78b Join unflag tokens, filter knobs by unflags, pin every table verbatim, guard degenerate ld output and empty lib flags 2026-08-20 23:57:45 -05:00
J. Nick Koston e5a7243b7b Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 23:55:47 -05:00
J. Nick Koston 662978c402 Name dropped requests and non-platform dependency rejections, correct the dot_a_linkage attribution 2026-08-20 23:55:38 -05:00
J. Nick Koston e6bf3e0e8f Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 23:55:19 -05:00
J. Nick Koston 078bcba473 Backend-neutral unsupported-core message, pin the PIO source formatter 2026-08-20 23:55:15 -05:00
J. Nick Koston 85acafb646 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 23:54:17 -05:00
J. Nick Koston 18a2aa2097 Probe the PATH ninja, chain import errors, harden registry payload checks, honest ccache docstring 2026-08-20 23:53:40 -05:00
J. Nick Koston f8d3df8196 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-20 23:48:20 -05:00
J. Nick Koston 21dfa0846e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 23:47:51 -05:00
J. Nick Koston d18b778462 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 23:47:51 -05:00
J. Nick Koston d58291945c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 23:47:51 -05:00
J. Nick Koston 88f1c4474f Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 23:47:51 -05:00
J. Nick Koston 6ed01b06c3 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 23:47:51 -05:00
J. Nick Koston 24eb6354f9 Run validators when a CLI toolchain is given on the cache fast path, cover every LibreTiny family 2026-08-20 23:47:47 -05:00
J. Nick Koston 5311be5c91 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 22:08:44 -05:00
J. Nick Koston 553adf6d24 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 22:08:44 -05:00
J. Nick Koston e220109c20 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 22:08:44 -05:00
J. Nick Koston d8bdf2fc5b Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 22:08:43 -05:00
J. Nick Koston 355d02ee6a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 22:08:43 -05:00
J. Nick Koston f5ac480dff Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 22:08:43 -05:00
J. Nick Koston 19555e8eaf Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 22:08:43 -05:00
J. Nick Koston d47dc0d992 Pin fingerprint stability and sensitivity behaviorally, note the platform pairing 2026-08-20 22:08:41 -05:00
J. Nick Koston 6e56d19615 Mirror the LookupError tolerance in the native post-build guard 2026-08-20 21:09:56 -05:00
J. Nick Koston 3e21c35e3e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 21:09:44 -05:00
J. Nick Koston 5b42eb3460 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 21:09:44 -05:00
J. Nick Koston 40c99b9c72 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 21:09:43 -05:00
J. Nick Koston c448174ea9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 21:09:43 -05:00
J. Nick Koston 6a363c1746 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 21:09:43 -05:00
J. Nick Koston b0a214830a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 21:09:43 -05:00
J. Nick Koston 38744e4222 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 21:09:43 -05:00
J. Nick Koston 9624abcd57 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 21:09:42 -05:00
J. Nick Koston 2c229debe8 Best-effort bad encodings, dedupe append warnings, tolerate structurally odd compile DBs 2026-08-20 21:09:38 -05:00
J. Nick Koston 58911dc8bc Cover the missing-hook raise and the analyze-memory refusal 2026-08-20 21:01:14 -05:00
J. Nick Koston a242624ea6 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 20:53:32 -05:00
J. Nick Koston d4031bf207 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 20:53:32 -05:00
J. Nick Koston 170a180458 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 20:53:32 -05:00
J. Nick Koston 5857bfcf52 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 20:53:32 -05:00
J. Nick Koston a17300a4bb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 20:53:32 -05:00
J. Nick Koston 378a01a838 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 20:53:31 -05:00
J. Nick Koston e266a449e0 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 20:53:31 -05:00
J. Nick Koston 6a0ce046fd Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 20:53:31 -05:00
J. Nick Koston 6b6344b454 Cover the healthy post-compile idedata path 2026-08-20 20:53:30 -05:00
J. Nick Koston f0e3fb48c3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 20:48:33 -05:00
J. Nick Koston 64835cbf88 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 20:48:33 -05:00
J. Nick Koston f9d71398d5 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 20:48:33 -05:00
J. Nick Koston 51f477e2c7 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 20:48:32 -05:00
J. Nick Koston a0e82cd000 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 20:48:32 -05:00
J. Nick Koston a56c465d6d Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 20:48:32 -05:00
J. Nick Koston b3d908d10e Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 20:48:32 -05:00
J. Nick Koston 09fd3fb53b Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 20:48:32 -05:00
J. Nick Koston 73ab04330e Treat sys.exit(0) as script success, fail on an unreadable declared script 2026-08-20 20:48:30 -05:00
J. Nick Koston d22a941b24 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 20:46:31 -05:00
J. Nick Koston 4f1c08d3a4 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 20:46:31 -05:00
J. Nick Koston a997b306ea Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 20:46:31 -05:00
J. Nick Koston d883ed5f8a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 20:46:31 -05:00
J. Nick Koston a255f3b07c Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 20:46:31 -05:00
J. Nick Koston 57b69cae81 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 20:46:30 -05:00
J. Nick Koston 9fccf1ce33 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 20:46:30 -05:00
J. Nick Koston b8bb4453e0 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 20:46:30 -05:00
J. Nick Koston 91eed262c8 Repr zero-arg script exceptions, surface a None idedata after an IDF build 2026-08-20 20:46:15 -05:00
J. Nick Koston 1ab13c4291 Cache the native toolchain install and ccache store in CI 2026-08-20 20:45:02 -05:00
J. Nick Koston 1d6a62a8a5 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 20:44:26 -05:00
J. Nick Koston 611aa76f48 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 20:44:26 -05:00
J. Nick Koston 1ce0a456c9 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 20:44:26 -05:00
J. Nick Koston ee9045f021 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 20:44:26 -05:00
J. Nick Koston c1a0ed0d46 Reject only unknown package majors: 2.6.3+ cores share the package-major-3 encoding 2026-08-20 20:44:24 -05:00
J. Nick Koston 3f96590567 Backend-agnostic dispatch guards, positive native polarity, warn on dropped upload_speed 2026-08-20 20:44:08 -05:00
J. Nick Koston 77e9a1d991 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 20:42:44 -05:00
J. Nick Koston fe5325b007 Honor lib_archive, guard unknown boards by name, quote archive names, fix the asm flag filter 2026-08-20 20:42:23 -05:00
J. Nick Koston 68db655047 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 20:41:36 -05:00
J. Nick Koston 84a10031ee Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 20:41:36 -05:00
J. Nick Koston fdbd4157ff Carry lib_archive, warn on unresolvable deps, unquote rsp lines, fail empty archives, note deviations 2026-08-20 20:41:17 -05:00
J. Nick Koston eb0cb06951 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 20:39:33 -05:00
J. Nick Koston 4969d9bf4a Pin the lx106 layout, reject non-3.x cores, pin installer args, delegate ccache policy tests 2026-08-20 20:39:20 -05:00
J. Nick Koston 1c5441b69e Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 20:38:30 -05:00
J. Nick Koston ec8437fea2 Quote empty tokens, honest docstrings, strict registry payloads, required layout checks, honest patch targets 2026-08-20 20:38:09 -05:00
J. Nick Koston 8513dfeebd Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 20:36:32 -05:00
J. Nick Koston b42babf749 Route platformio build_unflags natively, correct the gate and fallback comments 2026-08-20 20:35:49 -05:00
J. Nick Koston e1c4984498 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 20:34:25 -05:00
J. Nick Koston 3063b9067a State what the fingerprint test actually pins 2026-08-20 20:34:24 -05:00
J. Nick Koston cbdfb37470 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 19:51:31 -05:00
J. Nick Koston 687291d92c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 19:51:31 -05:00
J. Nick Koston 48c5570784 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 19:51:31 -05:00
J. Nick Koston 5b56867c71 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 19:51:31 -05:00
J. Nick Koston a73180e073 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 19:51:30 -05:00
J. Nick Koston b7a3181d13 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 19:51:28 -05:00
J. Nick Koston 1958746ae0 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 19:51:28 -05:00
J. Nick Koston 62c27826ee Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 19:51:27 -05:00
J. Nick Koston c95e0b90f5 Raise on a traversing extraScript, survive sys.exit in vendored scripts, fix the caveats wording 2026-08-20 19:51:26 -05:00
J. Nick Koston 339f0c3092 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 19:29:29 -05:00
J. Nick Koston f1bd58c222 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 19:29:29 -05:00
J. Nick Koston fc26bc081b Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 19:29:29 -05:00
J. Nick Koston 2a09cd81d3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 19:29:29 -05:00
J. Nick Koston cc3f9be805 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 19:29:29 -05:00
J. Nick Koston b05efb0811 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 19:29:29 -05:00
J. Nick Koston 321bc3b459 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 19:29:28 -05:00
J. Nick Koston 84a3c39562 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 19:29:28 -05:00
J. Nick Koston 5cf2135038 Cover the warn-once dedup branch 2026-08-20 19:29:27 -05:00
J. Nick Koston 7aaa874150 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-20 19:26:19 -05:00
J. Nick Koston 5838111107 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 19:25:46 -05:00
J. Nick Koston 3466285547 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 19:25:46 -05:00
J. Nick Koston 5da6a2abeb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 19:25:46 -05:00
J. Nick Koston b3afd951fe Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 19:25:46 -05:00
J. Nick Koston 8dd065997f Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 19:25:46 -05:00
J. Nick Koston 13e84e9bff Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 19:25:45 -05:00
J. Nick Koston 7ad97697b2 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 19:25:45 -05:00
J. Nick Koston 5bd328e6c4 Fail on a declared-but-absent extraScript, warn once per unsupported env method, split and widen tests 2026-08-20 19:25:33 -05:00
J. Nick Koston c9dbf79970 Widen the post-build idedata guard the same way 2026-08-20 19:03:14 -05:00
J. Nick Koston bed3389faf Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 19:02:47 -05:00
J. Nick Koston 6825996e32 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 19:02:47 -05:00
J. Nick Koston 4990093540 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 19:02:47 -05:00
J. Nick Koston 878883bb67 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 19:02:47 -05:00
J. Nick Koston 5bdd387c2a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 19:02:47 -05:00
J. Nick Koston 8c671ae8ea Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 19:02:46 -05:00
J. Nick Koston ac1160de25 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 19:02:46 -05:00
J. Nick Koston 5cec72020f Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 19:02:46 -05:00
J. Nick Koston ef2f16713a Widen the post-compile idedata guard to every failure the comment promises 2026-08-20 19:02:35 -05:00
J. Nick Koston 406d5c87ed Warn instead of failing when the post-build idedata is unusable 2026-08-20 18:41:38 -05:00
J. Nick Koston 8e63fa3c2a Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain
# Conflicts:
#	tests/unit_tests/test_main.py
2026-08-20 18:41:07 -05:00
J. Nick Koston fec60a7ff8 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 18:40:47 -05:00
J. Nick Koston 604ceb3de3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 18:40:47 -05:00
J. Nick Koston 5605d079d4 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 18:40:46 -05:00
J. Nick Koston 0268abc1e4 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 18:40:46 -05:00
J. Nick Koston c103e4d974 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 18:40:46 -05:00
J. Nick Koston 06fc234b12 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 18:40:46 -05:00
J. Nick Koston 12f8b14418 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 18:40:46 -05:00
J. Nick Koston 790c6d6353 Drop the never-hitting parse memo, guard the post-compile idedata refresh, pin the kind map 2026-08-20 18:40:29 -05:00
J. Nick Koston 0186a0568b Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 18:28:28 -05:00
J. Nick Koston d342d0a246 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 18:28:28 -05:00
J. Nick Koston e1cbe5e586 Sort flag iteration for reproducible defines, pin the flag tables, wrap a missing compiler cleanly 2026-08-20 18:28:26 -05:00
J. Nick Koston a397fcf373 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 18:18:29 -05:00
J. Nick Koston b0b3017d78 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 18:18:29 -05:00
J. Nick Koston 294fc2dd54 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 18:18:29 -05:00
J. Nick Koston 0ae75b01d8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 18:18:29 -05:00
J. Nick Koston fdd2920dbc Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 18:18:29 -05:00
J. Nick Koston 47780fec6e Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra
# Conflicts:
#	esphome/platformio/toolchain.py
2026-08-20 18:18:26 -05:00
J. Nick Koston c3e7d37d29 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 18:18:07 -05:00
J. Nick Koston 77fa411f04 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 18:18:07 -05:00
J. Nick Koston bc6b997350 Restore the lazy shlex import, pin the probe convention, assert the shim diagnostics 2026-08-20 18:17:56 -05:00
J. Nick Koston 949a45b29d Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 17:54:09 -05:00
J. Nick Koston 6437a676b8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 17:54:09 -05:00
J. Nick Koston 0c0f482acf Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 17:54:08 -05:00
J. Nick Koston 1bdddcc55e Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 17:54:08 -05:00
J. Nick Koston 73cd9f75b4 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 17:54:08 -05:00
J. Nick Koston a5a1a017d0 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra
# Conflicts:
#	esphome/platformio/toolchain.py
2026-08-20 17:53:57 -05:00
J. Nick Koston 9f3df90dba Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 17:52:58 -05:00
J. Nick Koston e20c43520b Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 17:52:57 -05:00
J. Nick Koston 9b12934307 Reject a launcher compile DB by name before the probe, discard partial script captures, log dropped env keys 2026-08-20 17:52:54 -05:00
J. Nick Koston 63da361100 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 17:30:37 -05:00
J. Nick Koston cff6871bd7 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 17:30:37 -05:00
J. Nick Koston 38cab9a775 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 17:30:37 -05:00
J. Nick Koston b6ea116b16 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	tests/unit_tests/test_platformio_library.py
2026-08-20 17:30:36 -05:00
J. Nick Koston eb38afb569 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 17:30:00 -05:00
J. Nick Koston 60896b3533 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 17:30:00 -05:00
J. Nick Koston 46baef5231 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 17:29:59 -05:00
J. Nick Koston f93d46e684 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 17:29:59 -05:00
J. Nick Koston d33a097152 Name every skipped size line, best-effort script compile, unusable idedata returns None 2026-08-20 17:29:47 -05:00
J. Nick Koston ee27ba64c0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 17:12:52 -05:00
J. Nick Koston 53c07a2bb5 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 17:12:52 -05:00
J. Nick Koston e8482a3030 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 17:12:52 -05:00
J. Nick Koston b2452fe397 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	tests/unit_tests/test_platformio_library.py
2026-08-20 17:12:49 -05:00
J. Nick Koston 14a58b788d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 17:12:32 -05:00
J. Nick Koston 454f299cd2 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 17:12:31 -05:00
J. Nick Koston 70a3880c9f Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 17:12:31 -05:00
J. Nick Koston 8008eda57f Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 17:12:31 -05:00
J. Nick Koston 466f890e1f Clean errors for non-string flags, visible size-summary skips, partial extra-script capture 2026-08-20 17:12:19 -05:00
J. Nick Koston badf21e7b0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:56:37 -05:00
J. Nick Koston a59b0bfcf8 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:56:37 -05:00
J. Nick Koston f91b1bc84e Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:56:37 -05:00
J. Nick Koston 88a5cdb53c Bare flags in the manifest fixture join within an entry, as ParseFlags does 2026-08-20 16:56:36 -05:00
J. Nick Koston ab81ae8aec Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:55:09 -05:00
J. Nick Koston 6aec54d8c9 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:55:09 -05:00
J. Nick Koston 3943f24e55 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:55:09 -05:00
J. Nick Koston 70cf20640c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/espidf/component.py
2026-08-20 16:54:55 -05:00
J. Nick Koston 8af1b9a523 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:54:39 -05:00
J. Nick Koston 9c543c9776 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:54:39 -05:00
J. Nick Koston fd47d5bcd2 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:54:39 -05:00
J. Nick Koston 57b7f03e42 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 16:54:39 -05:00
J. Nick Koston 4ab2a7ba98 Join flag args per entry like ParseFlags, pin the launcher strip log, record the asm merge decision 2026-08-20 16:54:28 -05:00
J. Nick Koston ab7faccf2c Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:51:31 -05:00
J. Nick Koston b3927e0845 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:51:30 -05:00
J. Nick Koston 25e145362c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:51:30 -05:00
J. Nick Koston 370f83769c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:51:30 -05:00
J. Nick Koston 96aabe428a Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:51:30 -05:00
J. Nick Koston cb2dfddf17 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:51:30 -05:00
J. Nick Koston 20f0e37f43 Cover the unresolved-toolchain ordering guard 2026-08-20 16:51:29 -05:00
J. Nick Koston ba569e72ec Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:46:52 -05:00
J. Nick Koston bb5c0ff930 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:46:52 -05:00
J. Nick Koston 5fa5b93201 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:46:52 -05:00
J. Nick Koston 8e25bfddb2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:46:52 -05:00
J. Nick Koston f4eefa111d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:46:52 -05:00
J. Nick Koston 2bbca6229a Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:46:51 -05:00
J. Nick Koston a50c4db187 Type the toolchain factories, guard the legacy libretiny stub, tighten the gate comments 2026-08-20 16:46:48 -05:00
J. Nick Koston 71fffcf410 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:34:32 -05:00
J. Nick Koston b82cc8be65 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:34:32 -05:00
J. Nick Koston d1889d09da Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:34:32 -05:00
J. Nick Koston e918d37aa8 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:34:31 -05:00
J. Nick Koston 1ecbb57b24 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:34:31 -05:00
J. Nick Koston 2e0b330366 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:34:31 -05:00
J. Nick Koston aea97d1022 Cover the arduino toolchain predicate 2026-08-20 16:34:21 -05:00
J. Nick Koston 301e7efad5 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:30:27 -05:00
J. Nick Koston 1bc9312ed7 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:30:27 -05:00
J. Nick Koston 41cb973eee Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:30:27 -05:00
J. Nick Koston 6392620f6c Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:30:27 -05:00
J. Nick Koston 65f5c302c5 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 16:30:26 -05:00
J. Nick Koston 16be3b1bbb Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:30:26 -05:00
J. Nick Koston 84940f1726 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:30:26 -05:00
J. Nick Koston 519ea38d73 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:30:26 -05:00
J. Nick Koston a0f0ad8729 Restore the underscore in test_parse_library_json 2026-08-20 16:30:13 -05:00
J. Nick Koston 5d10240521 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:25:49 -05:00
J. Nick Koston 137f58f00e Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:25:49 -05:00
J. Nick Koston d80bfb39d2 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:25:49 -05:00
J. Nick Koston 7f033fd993 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:25:49 -05:00
J. Nick Koston 51af18cdfb Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 16:25:48 -05:00
J. Nick Koston efacdd57ac Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:25:48 -05:00
J. Nick Koston 2280d3352d Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:25:48 -05:00
J. Nick Koston 0fad14be59 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:25:48 -05:00
J. Nick Koston 57a9c71da8 Cover the malformed build.flags rejection 2026-08-20 16:25:47 -05:00
J. Nick Koston baedceb8b6 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:24:56 -05:00
J. Nick Koston 5f09bf868d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 16:24:56 -05:00
J. Nick Koston 2579c11889 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:24:56 -05:00
J. Nick Koston 04422a0437 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts:
#	esphome/platformio/library.py
2026-08-20 16:24:54 -05:00
J. Nick Koston 3d8a3c6527 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 16:24:32 -05:00
J. Nick Koston e618c99f7d Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:24:32 -05:00
J. Nick Koston 89df2787f2 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:24:32 -05:00
J. Nick Koston 53f1cc116a Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:24:32 -05:00
J. Nick Koston 1483b7c10b Detect launchers by a closed denylist instead of guessing compiler names 2026-08-20 16:24:21 -05:00
J. Nick Koston f747322bc0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:21:04 -05:00
J. Nick Koston 6eaa43a7b2 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-20 16:21:03 -05:00
J. Nick Koston 1576a592e2 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:20:45 -05:00
J. Nick Koston e121fd3a37 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:20:45 -05:00
J. Nick Koston c8e816bf48 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:20:45 -05:00
J. Nick Koston 53935615f1 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:20:45 -05:00
J. Nick Koston 360c51329c Cover the native-toolchain predicate 2026-08-20 16:20:37 -05:00
J. Nick Koston 52aafc3af6 Drop the escaping test superseded by the shared ninja module tests 2026-08-20 16:20:19 -05:00
J. Nick Koston 2cb5e8d818 Warn on a failing addr2line on the PlatformIO path too 2026-08-20 16:15:42 -05:00
J. Nick Koston 0f40f23ec4 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:15:16 -05:00
J. Nick Koston 5c36fefe21 Drop the escaping test duplicated by the shared ninja module tests 2026-08-20 16:15:15 -05:00
J. Nick Koston e12bad27bb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 16:14:26 -05:00
J. Nick Koston c3f7ce7a02 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-20 16:14:24 -05:00
J. Nick Koston 57561e5a4d Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:14:04 -05:00
J. Nick Koston 10b13558c3 Line-oriented rspfile expansion, adopt the public manifest parser, document the dependency policy 2026-08-20 16:13:55 -05:00
J. Nick Koston 2e183f262b Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:13:21 -05:00
J. Nick Koston d82c2eaeb1 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:13:21 -05:00
J. Nick Koston 37de984df5 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 16:13:20 -05:00
J. Nick Koston c96c05eea4 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-build-infra 2026-08-20 16:13:20 -05:00
J. Nick Koston 2cf4087e2f Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:13:20 -05:00
J. Nick Koston 7fe0847e5c Update espidf test to the public parse_library_json name 2026-08-20 16:13:19 -05:00
J. Nick Koston 80815f1dc7 Make parse_library_json public alongside its properties sibling 2026-08-20 16:12:52 -05:00
J. Nick Koston 252422c706 Match ASPPCOM flag routing, quote manifest link tokens, split the src-dir error, pin the change contract 2026-08-20 16:12:28 -05:00
J. Nick Koston 0d794ce678 Lex every build flag entry, warn on custom MMU sizes without the knob, note the scanf omission 2026-08-20 16:10:02 -05:00
J. Nick Koston 5b19c139cb Force-quote shell metacharacters outside the safe token set 2026-08-20 16:09:09 -05:00
J. Nick Koston c629e4a94c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
# Conflicts:
#	esphome/build_gen/arduino8266.py
#	tests/unit_tests/build_gen/test_arduino8266.py
2026-08-20 16:07:57 -05:00
J. Nick Koston 0171af9f67 Adopt the shared ninja quoting helpers and typed install paths in the build spec 2026-08-20 16:07:22 -05:00
J. Nick Koston e187522490 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer 2026-08-20 16:06:32 -05:00
J. Nick Koston 6982cfeb9a Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:06:32 -05:00
J. Nick Koston 57c956dfc3 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:06:32 -05:00
J. Nick Koston 79b8bf2657 Carry the ninja escaping and quoting helpers with tests 2026-08-20 16:06:30 -05:00
J. Nick Koston e95869c656 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 16:05:20 -05:00
J. Nick Koston f9705772bb Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 16:05:19 -05:00
J. Nick Koston e36b8c5446 Point the ccache probe patch at its new module 2026-08-20 16:04:43 -05:00
J. Nick Koston 9c52c349d6 Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer
# Conflicts:
#	esphome/components/nrf52/framework.py
#	esphome/espidf/framework.py
#	esphome/framework_helpers.py
#	esphome/platformio/toolchain.py
2026-08-20 16:04:05 -05:00
J. Nick Koston d4861d89b0 Add the shared registry, ninja, ccache, and tools-cache infrastructure for native toolchains 2026-08-20 16:03:38 -05:00
J. Nick Koston 3166136db0 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 16:02:03 -05:00
J. Nick Koston 8f5f349e1b Pin the decoy anchor, guard unselected segments, fingerprint the module source 2026-08-20 16:01:06 -05:00
J. Nick Koston 83b4da1777 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 15:59:10 -05:00
J. Nick Koston 12c1b15578 Reject malformed build.flags by name and pin the idedata cache-hit path 2026-08-20 15:59:03 -05:00
J. Nick Koston 15f21342d0 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 15:55:02 -05:00
J. Nick Koston 1aece78707 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 15:55:02 -05:00
J. Nick Koston 219bf6ff71 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 15:55:02 -05:00
J. Nick Koston 7796911837 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 15:55:02 -05:00
J. Nick Koston e6debb980d Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-framework-installer 2026-08-20 15:55:01 -05:00
J. Nick Koston b3d5fccba5 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 15:55:01 -05:00
J. Nick Koston 6a84d67786 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 15:55:01 -05:00
J. Nick Koston ed48f36fa8 Route native dispatch through a platform hook, hoist the pio-options warner, adopt shared toolchain factories 2026-08-20 15:53:58 -05:00
J. Nick Koston b3a0856afd Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 15:49:05 -05:00
J. Nick Koston aa4dd3d0a1 Hoist the ninja quoting helpers, type the installed paths, format flash size from board data 2026-08-20 15:48:56 -05:00
J. Nick Koston 8f40b00fc3 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 15:46:56 -05:00
J. Nick Koston 6476fcbe1c Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 15:46:48 -05:00
J. Nick Koston d4e3603a19 Drop the dead name injection and pass board_mcu lazily 2026-08-20 15:46:39 -05:00
J. Nick Koston e032f37e04 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 15:46:18 -05:00
J. Nick Koston b90aeb17e3 Hoist find_ninja to build_helpers, type the installed paths, dedupe espidf ccache env 2026-08-20 15:46:07 -05:00
J. Nick Koston 3a51514fc1 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-framework-installer 2026-08-20 15:44:34 -05:00
J. Nick Koston 6ad3e0d8ad Add toolchain validator factories and a native-toolchain predicate 2026-08-20 15:44:23 -05:00
J. Nick Koston 7a3f700206 Act on bad-compiler detection, atomic logged idedata cache, memoized entry parsing, callable board_mcu 2026-08-20 15:41:39 -05:00
J. Nick Koston cbd5e08aa9 Adopt the shared size line printer and cover the moved modules in the native CI triggers 2026-08-20 15:30:03 -05:00
J. Nick Koston d736b0d1eb Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 15:29:04 -05:00
J. Nick Koston ea429ffdb6 Derive the suffix rule map, dedupe quoting and unflag filtering, adopt the moved library backend 2026-08-20 15:28:55 -05:00
J. Nick Koston a46a8f4832 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 15:27:10 -05:00
J. Nick Koston 4ef65315de Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 15:27:09 -05:00
J. Nick Koston 857bcaef4d Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 15:27:09 -05:00
J. Nick Koston 5a5496f7f7 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-framework-installer
# Conflicts:
#	esphome/platformio/toolchain.py
2026-08-20 15:26:58 -05:00
J. Nick Koston 9d9953ea47 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 15:26:39 -05:00
J. Nick Koston 7d9c18a330 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 15:26:38 -05:00
J. Nick Koston ca47309a36 Move the Arduino library backend to esphome/arduino and close_fds the ar shim 2026-08-20 15:26:17 -05:00
J. Nick Koston 113259275c Move the PlatformIO registry installer to esphome.platformio.registry and transliterate get_systype 2026-08-20 15:25:12 -05:00
J. Nick Koston 5a4337c240 Share the size line format, derive source extensions from a kind map, close_fds on the ccache probe 2026-08-20 15:21:31 -05:00
J. Nick Koston 8043767460 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 15:13:09 -05:00
J. Nick Koston e981e6014d Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 15:13:08 -05:00
J. Nick Koston 1094e3e085 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 15:13:08 -05:00
J. Nick Koston 2508899cad Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 15:13:08 -05:00
J. Nick Koston 1c7b4275ad Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 15:12:49 -05:00
J. Nick Koston 7dca5da948 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 15:12:49 -05:00
J. Nick Koston d9cea818b4 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 15:12:49 -05:00
J. Nick Koston 38b6f222b5 Use a host table and the shared downloader for registry metadata 2026-08-20 15:12:37 -05:00
J. Nick Koston 5d173d851e Cover the idedata failure warning after a successful build 2026-08-20 14:53:58 -05:00
J. Nick Koston 2c883a2c26 Toolchain-suffixed idedata cache, surfaced idedata failures, and per-dump decode warnings 2026-08-20 14:48:18 -05:00
J. Nick Koston 258417d7d3 Merge branch 'esp8266-native-library-backend' into esp8266-arduino-toolchain 2026-08-20 14:47:14 -05:00
J. Nick Koston 8bbaa09891 Expand ar response files in the shim and honor bundled library.json manifests 2026-08-20 14:46:09 -05:00
J. Nick Koston 976a5ed988 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 14:44:21 -05:00
J. Nick Koston c72de504fd Hard install lock, ninja-first install order, enforced floor, backoff, and by-name host failures everywhere 2026-08-20 14:43:48 -05:00
J. Nick Koston ff167e5193 Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-framework-installer 2026-08-20 14:41:55 -05:00
J. Nick Koston 2861cbb749 Harden the shared toolchain check and pin every platform family's rejection 2026-08-20 14:41:23 -05:00
J. Nick Koston 8bf699cf79 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 14:39:21 -05:00
J. Nick Koston 375cf95240 Anchor the segment regex, reject unknown segments, and pin real-script fixtures 2026-08-20 14:38:25 -05:00
J. Nick Koston d6a9fd5238 Adopt the shared toolchain check, dedupe the native-module dispatch, and complete the trigger set 2026-08-20 14:32:31 -05:00
J. Nick Koston 421f648a07 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 14:30:15 -05:00
J. Nick Koston a0d56d02d0 Tighten the emission half: shared srcflags, single escapes, one testing-name derivation 2026-08-20 14:29:54 -05:00
J. Nick Koston b384483fdc Merge branch 'esp8266-native-framework-installer' into esp8266-arduino-toolchain 2026-08-20 14:24:43 -05:00
J. Nick Koston 796172ce1a Merge branch 'esp8266-native-framework-installer' into esp8266-native-build-spec 2026-08-20 14:24:42 -05:00
J. Nick Koston f5fc145dd3 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 14:24:42 -05:00
J. Nick Koston d330d6ff99 Merge branch 'esp8266-native-framework-installer' into esp8266-native-ninja-emission 2026-08-20 14:24:42 -05:00
J. Nick Koston f44398b09e Fix the remaining ccache probe patch target 2026-08-20 14:24:28 -05:00
J. Nick Koston 0f56a37242 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 14:22:17 -05:00
J. Nick Koston 866c59384c Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 14:22:05 -05:00
J. Nick Koston cd0c3bb069 Keep the spec half honest: fingerprint-stamped ld cache, MMU table, emission helpers deferred 2026-08-20 14:19:53 -05:00
J. Nick Koston 9d54e87c70 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 14:17:02 -05:00
J. Nick Koston d64592d2ea Simplify library classification, share the manifest flag lexing, and home the build tool with the generators 2026-08-20 14:16:46 -05:00
J. Nick Koston 102973524e Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 14:14:47 -05:00
J. Nick Koston 1307cc25c5 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 14:14:44 -05:00
J. Nick Koston 353ef2dee1 Merge branch 'esp8266-native-build-surgery' into esp8266-native-framework-installer 2026-08-20 14:14:44 -05:00
J. Nick Koston 18e3eac419 Export a surgery fingerprint for linker-script cache stamps 2026-08-20 14:14:32 -05:00
J. Nick Koston e77102e9a8 Merge branch 'esp8266-native-framework-installer' into esp8266-arduino-toolchain 2026-08-20 14:07:49 -05:00
J. Nick Koston 83d9351925 Merge branch 'esp8266-native-framework-installer' into esp8266-native-ninja-emission 2026-08-20 14:07:48 -05:00
J. Nick Koston b3faae60f2 Merge branch 'esp8266-native-framework-installer' into esp8266-native-build-spec 2026-08-20 14:07:48 -05:00
J. Nick Koston 18f39a0e53 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 14:07:48 -05:00
J. Nick Koston d9cc72c650 Point the ccache tests at the shared helpers 2026-08-20 14:07:34 -05:00
J. Nick Koston 5aecdd9c7a Point the ccache tests at the shared helpers 2026-08-20 14:06:43 -05:00
J. Nick Koston b584085af2 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 14:05:09 -05:00
J. Nick Koston d4c4424587 Merge branch 'esp8266-native-framework-installer' into esp8266-native-ninja-emission 2026-08-20 14:04:54 -05:00
J. Nick Koston 87276a8ca5 Merge branch 'esp8266-native-framework-installer' into esp8266-native-build-spec 2026-08-20 14:04:53 -05:00
J. Nick Koston f0f9af2ad6 Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend 2026-08-20 14:04:53 -05:00
J. Nick Koston 0fe9d87124 Share the ccache and tools-path helpers across the native backends 2026-08-20 14:04:38 -05:00
J. Nick Koston 5398ca98eb Merge branch 'esp8266-native-toolchain-plumbing' into esp8266-native-framework-installer 2026-08-20 13:59:14 -05:00
J. Nick Koston bbf2788684 Share one unsupported-toolchain check across platforms 2026-08-20 13:58:46 -05:00
J. Nick Koston c7e1d044a3 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 13:57:53 -05:00
J. Nick Koston 0620ce81c3 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 13:57:51 -05:00
J. Nick Koston 2564ad0deb Warn once per non-compiler path, accept versioned compiler names, and pin the trigger table 2026-08-20 13:57:30 -05:00
J. Nick Koston 3f70f11b71 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 13:50:10 -05:00
J. Nick Koston 73132ba852 Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission 2026-08-20 13:49:45 -05:00
J. Nick Koston 0d3333f245 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 13:49:09 -05:00
J. Nick Koston 03d5b131ca Adopt the relocated extraScript helper and its neutral parameter 2026-08-20 13:48:56 -05:00
J. Nick Koston 0ed4c47b66 Adopt the exact-segments surgery API 2026-08-20 13:48:16 -05:00
J. Nick Koston 3ac8ff1176 Merge branch 'esp8266-native-build-surgery' into esp8266-native-library-backend 2026-08-20 13:44:30 -05:00
J. Nick Koston 8e5b9dca03 Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec 2026-08-20 13:44:30 -05:00
J. Nick Koston fa45c4a016 Merge branch 'esp8266-native-build-surgery' into esp8266-native-framework-installer 2026-08-20 13:44:29 -05:00
J. Nick Koston 3d7c0eac57 Merge branch 'esp8266-native-build-surgery' into esp8266-native-toolchain-plumbing 2026-08-20 13:44:29 -05:00
J. Nick Koston e3936f500f Patch exactly the named segments and share the segment-line pattern 2026-08-20 13:44:12 -05:00
J. Nick Koston cea86989c9 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 13:42:37 -05:00
J. Nick Koston e82453e80e Complete the unit-test package chain so test modules import fully qualified 2026-08-20 13:42:15 -05:00
J. Nick Koston 3eec5085da Give the format_bar tests a unique basename 2026-08-20 13:39:46 -05:00
J. Nick Koston 57c8648210 Drop the test package init that collides with script/build_helpers.py on the CI path 2026-08-20 13:38:54 -05:00
J. Nick Koston aa3c15d098 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 13:37:23 -05:00
J. Nick Koston d3524db735 Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 13:35:53 -05:00
J. Nick Koston 340f098872 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-ninja-emission 2026-08-20 13:35:43 -05:00
J. Nick Koston c5afb0b665 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-spec 2026-08-20 13:35:43 -05:00
J. Nick Koston 8f9aca154f Merge branch 'esp8266-native-shared-helpers' into esp8266-native-library-backend 2026-08-20 13:35:42 -05:00
J. Nick Koston 1db7309f4a Merge branch 'esp8266-native-shared-helpers' into esp8266-native-framework-installer 2026-08-20 13:35:42 -05:00
J. Nick Koston 1d0a1d2b38 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-toolchain-plumbing 2026-08-20 13:35:42 -05:00
J. Nick Koston 46fa42fa33 Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery 2026-08-20 13:35:42 -05:00
J. Nick Koston 9bd548ba92 Move the extraScript machinery into the platformio package and tidy the extraction 2026-08-20 13:35:07 -05:00
J. Nick Koston 5993a5acfa Merge branch 'esp8266-native-ninja-emission' into esp8266-arduino-toolchain 2026-08-20 13:04:59 -05:00
J. Nick Koston 207968f301 Add the ESP8266 native ninja emission 2026-08-20 13:03:50 -05:00
J. Nick Koston 61e32230d9 Add the ESP8266 native build spec (knobs, defines, flags, linker scripts) 2026-08-20 13:02:52 -05:00
J. Nick Koston 82c3c1f50a Add the ESP8266 native library backend 2026-08-20 12:59:10 -05:00
J. Nick Koston 3e77654719 Add the ESP8266 Arduino framework and toolchain installer 2026-08-20 12:58:06 -05:00
J. Nick Koston 04ad9524f5 Add the arduino toolchain enum and validate --toolchain on every platform 2026-08-20 12:56:34 -05:00
J. Nick Koston 72da2b1ce2 Add the ESP8266 linker-script surgery and board build metadata 2026-08-20 12:53:50 -05:00
J. Nick Koston 9ddcd6336e Merge branch 'esp8266-native-shared-helpers' into esp8266-arduino-toolchain 2026-08-20 12:51:01 -05:00
J. Nick Koston ab58f1080a Cover the tidy-project idedata assembly and hoist its helper import 2026-08-20 12:50:56 -05:00
J. Nick Koston 898bb78c7b Merge branch 'esp8266-native-shared-helpers' into esp8266-arduino-toolchain 2026-08-20 12:48:03 -05:00
J. Nick Koston 47942fb166 Note the upstream spelling in the format_bar citation 2026-08-20 12:47:54 -05:00
J. Nick Koston c96360d83c Merge branch 'esp8266-native-shared-helpers' into esp8266-arduino-toolchain 2026-08-20 12:46:43 -05:00
J. Nick Koston f326c3f04d Move the shared helpers into a neutral build_helpers package 2026-08-20 12:43:34 -05:00
J. Nick Koston 3b51ec2ae7 Extract the shared native-build helpers from the ESP-IDF backend 2026-08-20 12:36:42 -05:00
J. Nick Koston 96c1b90f19 Merge remote-tracking branch 'origin/dev' into esp8266-arduino-toolchain 2026-08-20 12:32:30 -05:00
J. Nick Koston 100dc04b38 Re-glue spaced -D tokens so knob defines are detected like PlatformIO 2026-08-20 11:37:28 -05:00
J. Nick Koston 7a2eaad9ce Warn when a compile entry does not lead with a compiler and fail on an empty core archive 2026-08-20 10:48:58 -05:00
J. Nick Koston 785260626e Warn once per missing decode tool and document the launcher-free ESP-IDF compile database 2026-08-20 10:45:36 -05:00
J. Nick Koston 1477de24d3 Skip the RAM and Flash summary lines together when the flash budget is unknown 2026-08-20 10:09:57 -05:00
J. Nick Koston 069ae156f9 Strip the exact configured launcher from compile commands instead of guessing by name 2026-08-20 09:55:15 -05:00
J. Nick Koston 0d38e47646 Share the argv quoting core between path and token quoting 2026-08-20 09:42:49 -05:00
J. Nick Koston d614e91753 Cross-platform token quoting, ninja-safe dollar escaping, and a tighter install path 2026-08-20 09:38:44 -05:00
J. Nick Koston a90dd88aa8 Lex every build_flags entry with re-quoted emission and lock the shared cache install 2026-08-20 09:33:49 -05:00
J. Nick Koston 47564d3a74 Merge branch 'dev' into esp8266-arduino-toolchain 2026-08-20 09:06:15 -05:00
J. Nick Koston 4eeceded0d Make the testing-mode require explicit, reject a missing declared srcDir, and validate installs before marking success 2026-08-20 08:08:29 -05:00
J. Nick Koston 0defff2c81 Warn when component-added platformio options are dropped by the native build 2026-08-20 07:53:16 -05:00
J. Nick Koston 0e561d8c1f Surface malformed build flag entries as clean errors 2026-08-20 07:47:54 -05:00
J. Nick Koston 2d93300903 Detect knobs in multi-token build_flags entries and drop a zero flash budget with a warning 2026-08-20 07:39:14 -05:00
J. Nick Koston a005008cfb Retry registry queries and surface failures as clean errors 2026-08-20 07:34:41 -05:00
J. Nick Koston dad9a1175b Reject unsupported toolchains on the PlatformIO-only platforms and warn on empty srcFilter matches 2026-08-20 06:52:54 -05:00
J. Nick Koston 42e9448a50 Cover the YAML toolchain key resolution 2026-08-20 06:48:24 -05:00
J. Nick Koston eaae2e543b Reject unsupported CLI toolchains on every platform and complete the native CI triggers 2026-08-20 06:30:07 -05:00
J. Nick Koston 4520f27d94 Raise the actionable ninja message when the package itself is missing 2026-08-20 06:17:10 -05:00
J. Nick Koston 3f9568eaf0 Fail loudly on hosts with no toolchain build instead of assuming linux_x86_64 2026-08-20 06:02:20 -05:00
J. Nick Koston aa03404319 Close the native CI trigger gap and log the remaining silent library skips 2026-08-20 05:35:17 -05:00
J. Nick Koston 2483117648 Store the native version floor as a Version and tidy the dependency skip 2026-08-20 05:25:25 -05:00
J. Nick Koston ff7161d7eb Surface silently dropped inputs and anchor the platform defaults to shared constants 2026-08-20 05:21:41 -05:00
J. Nick Koston 4f11db4232 Reject framework 3.1.0 (no registry package) and warn when platform_version is ignored 2026-08-20 05:16:51 -05:00
J. Nick Koston 311f610787 Make the link-line and tool-path tests platform-independent 2026-08-20 05:10:58 -05:00
J. Nick Koston 7f2515edf1 Share the PlatformIO flag-lexing helper and flatten the build_flags classifier 2026-08-20 05:03:49 -05:00
J. Nick Koston eb3a64829f Shell-lex -L/-l build_flags entries and generate the compile database before the build 2026-08-20 04:59:27 -05:00
J. Nick Koston 7cb22725e3 Escape object paths once at the source and drop a dead parameter 2026-08-20 04:39:50 -05:00
J. Nick Koston db010d486e Revert ninja command quoting (ninja escapes its own path variables); share the lib_ignore helper 2026-08-20 04:31:01 -05:00
J. Nick Koston c579a2792f Address review: quote ninja command paths, refuse unverified downloads, extend lib_ignore and build_unflags parity 2026-08-20 04:23:14 -05:00
J. Nick Koston 005c01e1e2 Address review: Windows binutils suffix, honor build_unflags against framework flags 2026-08-20 03:51:08 -05:00
J. Nick Koston 59c309083d Address review: include surgery constants in the ld stamp, require size sections, warn on missing extraScript 2026-08-20 03:36:44 -05:00
J. Nick Koston 9cf7ff94ac Resolve bare registry libraries at latest version like PlatformIO; tighten review cleanups 2026-08-20 03:07:07 -05:00
J. Nick Koston 702ef56a88 Address review: route project -L/-l to the link, fail on unresolvable libraries, remove dead ninja constants, tighten diagnostics 2026-08-20 02:54:00 -05:00
J. Nick Koston 7065beaabc Cover the native toolchain dispatch branches in idedata and analyze-memory 2026-08-20 01:53:50 -05:00
J. Nick Koston e331813299 Get ninja from the PyPI wheel instead of hardcoded release URLs and checksums 2026-08-20 01:52:07 -05:00
J. Nick Koston 0c48f749c2 Fix testing-mode segment requirements per linker script; simplify downloads and native command dispatch 2026-08-20 01:45:39 -05:00
J. Nick Koston 3ae229f218 Fix analyze-memory test path expectations on Windows 2026-08-20 01:38:21 -05:00
J. Nick Koston 5df08d36be Address review: wire analyze-memory and idedata for the native toolchain, warn on ignored platformio_options, verify downloads, surface silent failures 2026-08-20 01:34:15 -05:00
J. Nick Koston 60b7b874f1 Address review: route versioned bare libraries to the registry, deterministic MMU order, scoped toolchain branches, diagnostics 2026-08-20 00:00:51 -05:00
J. Nick Koston 66f6f5c004 Address review: cover all source suffixes, pass PIOPLATFORM through, link library -Wl flags 2026-08-19 23:50:16 -05:00
J. Nick Koston 9429243d2b Fix determine-jobs narrowing helper and add esp8266-native tests 2026-08-19 23:19:52 -05:00
J. Nick Koston 3fe9cac1fc Apply review cleanups to the native ESP8266 toolchain 2026-08-19 23:13:30 -05:00
J. Nick Koston 8811224c0e Add full test coverage for the native ESP8266 toolchain 2026-08-19 22:59:05 -05:00
J. Nick Koston 373bee8aca [esp8266] Add native toolchain that builds the Arduino core without PlatformIO 2026-08-19 22:31:46 -05:00
J. Nick Koston 28384673f6 Merge branch 'dev' into espidf_parallel_tool_prefetch 2026-08-19 16:32:48 -05:00
J. Nick Koston b361342bde Do not end a progress bar that never drew a frame 2026-08-19 15:13:04 -05:00
J. Nick Koston d34eed6d2d Merge branch 'dev' into espidf_parallel_tool_prefetch 2026-08-19 14:41:44 -05:00
J. Nick Koston 12238eec3b Log prefetch failures after the bar, assert on the shared progress instance 2026-08-19 13:57:15 -05:00
J. Nick Koston fe53ff6b6b Finish the batch bar, cancel queued archives on Ctrl-C, report known sizes 2026-08-19 13:28:42 -05:00
J. Nick Koston d0f38d7644 [espidf] Download tool archives in parallel during the install prefetch 2026-08-19 12:03:39 -05:00
8144 changed files with 77946 additions and 389086 deletions

No files matched your search

-241
View File
@@ -1,241 +0,0 @@
---
name: automations
description: Write ESPHome automation building blocks - triggers (on_* keys), actions and conditions. Use when adding or changing an on_* trigger, an action such as my_component.do_something, a condition, a callback registration method (add_on_*_callback), or code that calls build_callback_automation, build_automation, register_*_action or register_*_condition.
---
# Automations: triggers, actions and conditions
Automations have three building blocks: **Triggers** (fire when something happens), **Actions** (do
something), and **Conditions** (check if something is true). The helpers named here are documented in
their docstrings in `esphome/automation.py`.
## Triggers: callback method (preferred)
Use `build_callback_automation()` for simple triggers. This eliminates the need for a C++ Trigger class by
using a lightweight pointer-sized forwarder struct registered directly as a callback. No `CONF_TRIGGER_ID`
in the schema.
**Python:**
```python
from esphome import automation
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(MyComponent),
cv.Optional(CONF_ON_STATE): automation.validate_automation({}),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
for conf in config.get(CONF_ON_STATE, []):
await automation.build_callback_automation(
var, "add_on_state_callback", [(bool, "x")], conf
)
```
`build_callback_automation` arguments: `parent`, `callback_method` (C++ method name), `args` (template args
as `[(type, name)]` tuples), `config`, and optional `forwarder` (defaults to `TriggerForwarder<Ts...>`).
For boolean filtering (e.g. `on_press`/`on_release`), use built-in forwarders with `args=[]`:
```python
for conf_key, forwarder in (
(CONF_ON_PRESS, automation.TriggerOnTrueForwarder),
(CONF_ON_RELEASE, automation.TriggerOnFalseForwarder),
):
for conf in config.get(conf_key, []):
await automation.build_callback_automation(
var, "add_on_state_callback", [], conf, forwarder=forwarder
)
```
When the callback's parameters differ from the automation's arguments, or the trigger should only fire for
some values, pass `params`, `forward` and `when`; the helper then generates a capture-less lambda (stored
inline, nothing allocated). Name the parent with `automation.parent_ref(var)` and build `forward` from
`MockObj` calls, not f-strings of C++:
```python
parent = automation.parent_ref(var)
index = cg.RawExpression("index")
await automation.build_callback_automation(
var,
"add_on_state_callback",
[(cg.StringRef, "x"), (cg.size_t, "i")],
conf,
params=[(cg.size_t, "index")],
forward=[cg.StringRef(parent.option_at(index)), index],
)
```
`build_parent_callback_automation`, `build_trigger_callback`, `build_callback_automations` and
`build_trigger_automations` cover the other shapes; see their docstrings in `esphome/automation.py`.
When every action in a callback automation is inline (see Actions below), no `Automation` or action objects
are generated: the callback calls one generated function, at the same RAM cost as a hand-written lambda. A
custom forwarder blocks this unless its filter is also given as `params`, `forward` and `when`, so always pass
them together:
```python
automation.CallbackAutomation(
CONF_ON_IDLE,
"add_on_state_callback",
forwarder=StateEnterForwarder.template(State.IDLE),
params=[(State, "state")],
forward=[],
when=f"state == {State.IDLE}",
)
```
**C++: no trigger class needed.** The callback registration method must be templatized to accept both
`std::function` and lightweight forwarder structs (which avoid heap allocation):
```cpp
class MyComponent : public Component {
public:
// Must be a template -- accepts both std::function and pointer-sized forwarder structs
template<typename F> void add_on_state_callback(F &&callback) {
this->state_callback_.add(std::forward<F>(callback));
}
protected:
// Use CallbackManager when callbacks are always registered (e.g. core components)
CallbackManager<void(bool)> state_callback_;
// Use LazyCallbackManager when callbacks are often not registered -- saves 8 bytes
// (nullptr vs empty std::vector) per instance when no callbacks are added
// LazyCallbackManager<void(bool)> state_callback_;
};
```
Never type a registration method's parameter as `std::function`; that forces a heap allocation for every
forwarder struct:
```cpp
// Bad
void add_on_state_callback(std::function<void(bool)> &&callback) {
this->state_callback_.add(std::move(callback));
}
```
| Type | Idle overhead (32-bit) | When to use |
|------|----------------------|-------------|
| `CallbackManager<void(Ts...)>` | 12 bytes (empty `std::vector`) | Callbacks are always or almost always registered |
| `LazyCallbackManager<void(Ts...)>` | 4 bytes (`nullptr`) | Callbacks are often not registered (common case) |
| `AutomationList<N, Ts...>` + `build_automation_lists` | 4 bytes per automation + count, none when unused | A hub fires its own `on_*` automations with no filter (4 B per automation vs 8 B per `Callback`) |
| `automation.new_automation(args, conf)` + the parent's own fixed table | the table entry (pointer plus its own data) | Like `AutomationList`, but each automation needs a stored value of its own, e.g. a threshold the parent compares against |
Both live in `esphome/core/helpers.h` and accept `std::function`, lambdas and forwarder structs through
their templatized `add()` method. `LazyCallbackManager` is a drop-in replacement for `CallbackManager` that defers allocation until the first
callback is added. Prefer it for entity-level callbacks where most instances have no subscribers.
## Triggers: Trigger class method
Use `build_automation()` with a `Trigger<Ts...>` subclass only when the forwarder needs **mutable state
beyond a single `Automation*` pointer** (e.g. edge detection tracking previous state, timing logic).
**Python:**
```python
TurnOnTrigger = my_ns.class_("TurnOnTrigger", automation.Trigger.template())
CONFIG_SCHEMA = cv.Schema(
{
cv.Optional(CONF_ON_TURN_ON): automation.validate_automation(
{cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TurnOnTrigger)}
),
}
)
async def to_code(config):
for conf in config.get(CONF_ON_TURN_ON, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
```
**C++:**
```cpp
class TurnOnTrigger : public Trigger<> {
public:
explicit TurnOnTrigger(MyComponent *parent) : last_on_{false} {
parent->add_on_state_callback([this](bool state) {
if (state && !this->last_on_)
this->trigger();
this->last_on_ = state;
});
}
protected:
bool last_on_;
};
```
## Actions
```cpp
template<typename... Ts> class MyAction : public Action<Ts...> {
public:
explicit MyAction(MyComponent *parent) : parent_(parent) {}
void play(const Ts &...) override { this->parent_->do_something(); }
protected:
MyComponent *parent_;
};
```
Register it without writing a builder:
```python
automation.register_simple_action(
"my_component.do_something", MyAction, schema, synchronous=True
)
```
The constructor receives the object named by `config[CONF_ID]`. Use `register_bare_action` for a
no-argument constructor, `register_parented_action` for a class deriving from `Parented<T>`, and the
`@automation.register_action(...)` decorator only when the builder must also set fields.
Use `synchronous=True` for actions that run to completion inside `play()` without deferring. Use
`synchronous=False` if the action may suspend/defer execution (e.g. `delay`, `wait_until`, `script.wait`)
or store trigger arguments for later use.
**Actions that only forward templatable values to their parent need no C++ class.** Register them with
`register_apply_action`; do not write a `TEMPLATABLE_VALUE` class or a builder for this shape.
```python
automation.register_apply_action(
"my_component.set_gains",
schema,
automation.ApplyField(CONF_KP, "set_kp", cg.float_),
automation.ApplyField(CONF_KI, "set_ki", cg.float_),
)
```
The `ApplyField`, `ApplyCall` and `register_apply_action` docstrings in `esphome/automation.py` cover the
rest; `cover.control` and `cover.template.publish` are in-tree examples. An action whose input is a byte
payload passes `automation.ApplyBytes(CONF_DATA, "send({})")` in the same call; a constant payload stays in
flash and a lambda's vector is forwarded as data and size. `TEMPLATABLE_VALUE` with `cg.templatable` stays
for actions whose `play()` has real logic beyond forwarding values.
Adjacent `register_apply_action` and `lambda:` actions in a list merge into one generated function and one
object, which saves 12 to 16 bytes of RAM per merged action. An action with its own C++ class ends the merged
run, so prefer `register_apply_action` wherever the action allows it. Because of this, `build_action_list` can
return fewer objects than the config has entries. A builder that wraps `apply_action_builder` may do other work
first, but must return its result unchanged and not use it. A builder that must generate its own statements, and
is registered with `automation.ApplyAction`, can call `apply_statements_action` and still merge; `script.execute`
is an example. `if`, `choose`, `while` and `repeat` whose bodies are all inline become C++ control flow in the
same function, and `register_apply_condition` and `lambda:` conditions become plain expressions there.
## Conditions
```cpp
template<typename... Ts> class MyCondition : public Condition<Ts...> {
public:
explicit MyCondition(MyComponent *parent) : parent_(parent) {}
bool check(const Ts &...) override { return this->parent_->is_active(); }
protected:
MyComponent *parent_;
};
```
Register with `automation.register_simple_condition("my_component.is_active", MyCondition, schema)`;
`register_bare_condition`, `register_parented_condition` and the decorator follow the action rules.
**Conditions that only test their parent need no C++ class either.** Register them with
`register_apply_condition`; the expression is applied to the parent, and an `ApplyCall` compares against
config values.
```python
automation.register_apply_condition("my_component.is_active", schema, "is_active()")
automation.register_apply_condition(
"my_component.state_is",
schema,
automation.ApplyCall("state == {}", ((CONF_STATE, cg.bool_),)),
)
```
`cover.is_open`, `rtttl.is_playing` and `component.is_idle` are in-tree examples.
-68
View File
@@ -1,68 +0,0 @@
---
name: breaking-changes
description: Decide whether an ESPHome change breaks public API and handle it - what counts as public C++ and Python API, the deprecation window, ESPDEPRECATED for C++, cv.rename_key and deprecation warnings for config keys, and the migration notes a PR needs. Use when removing, renaming or changing the signature of a config option, a public C++ member or a core Python helper.
---
# Public API and breaking changes
Full policy: https://developers.esphome.io/contributing/code/#public-api-and-breaking-changes
## What is public
- **C++ in components:** only features documented at [esphome.io](https://esphome.io) are public API.
Undocumented `public` members are internal.
- **C++ core and base classes** (`esphome/core/`, `Component`, `Sensor`, etc.): all `public` members are
public API.
- **Components with global accessors** (`global_api_server`, etc.): all `public` members are public API
(except config setters).
- **Python:** all documented configuration options are public API. Python code in `esphome/core/` that
existing core components use is stable API. Other Python code is internal unless explicitly documented
for external component use.
- Changing the signature of a lambda that code generation injects is not a breaking change.
## Policy
- Aim for a **6-month deprecation window** when possible.
- Clean breaks are allowed for signature changes, deep refactorings and resource constraints.
- The migration path goes in the PR description (it generates the release notes).
- A blog post is required for core/base class changes or significant architectural changes.
Checklist:
- [ ] Clear justification (RAM/flash savings, architectural improvement)
- [ ] Explored non-breaking alternatives
- [ ] Added deprecation warnings if possible (`ESPDEPRECATED` for C++)
- [ ] Documented migration path in the PR description with before/after examples
- [ ] Updated all internal usage and esphome.io
- [ ] Tested backward compatibility during the deprecation period
## Deprecating C++
```cpp
// Remove before 2026.6.0
ESPDEPRECATED("Use new_method() instead. Removed in 2026.6.0", "2025.12.0")
void old_method() { this->new_method(); }
```
## Deprecating config keys
For a renamed key, use the shared `cv.rename_key` validator with `removed_in` (and `component` for
context); it warns and migrates automatically:
```python
CONFIG_SCHEMA = cv.All(
cv.rename_key(
CONF_OLD_KEY, CONF_NEW_KEY, removed_in="2026.6.0", component="my_component"
),
cv.Schema({...}),
)
```
For other deprecations, warn manually during validation:
```python
# Remove before 2026.6.0
if CONF_OLD_KEY in config:
_LOGGER.warning(
f"'{CONF_OLD_KEY}' deprecated, use '{CONF_NEW_KEY}'. Removed in 2026.6.0"
)
config[CONF_NEW_KEY] = config.pop(CONF_OLD_KEY) # Auto-migrate
```
Cover the old syntax with a `validate.*.yaml` test (see the `component-tests` skill), and keep the language
schema correct (see the `config-validation` skill).
+7 -72
View File
@@ -9,37 +9,15 @@ ESPHome parses YAML into C++ firmware for memory-constrained microcontrollers
(ESP32, ESP8266, RP2040, LibreTiny). Review changes with that in mind: RAM and
flash are scarce, and code runs unattended for months.
`AGENTS.md` in the repository root is the contributor guide, and the skills it
lists (`component-codegen`, `config-validation`, `automations`,
`embedded-memory`, `component-tests`, `breaking-changes`) hold the detail. They
are the authority when they disagree with this summary. The developer
documentation at https://developers.esphome.io explains the component lifecycle
and the reasoning behind these rules. This skill lists the concrete things worth
flagging in a review; read the matching skill for the detail behind any item.
`AGENTS.md` in the repository root is the full contributor guide and the
authority when it disagrees with this summary. The developer documentation at
https://developers.esphome.io explains the component lifecycle and the reasoning
behind these rules. This skill lists the concrete things worth flagging in a
review; read `AGENTS.md` for the detail behind any item.
Only raise findings that the diff actually introduces or changes. Do not ask for
drive-by cleanup of pre-existing code the PR did not touch.
## Scope: shared code does not ride a component PR
Check the file list first. A PR titled for one component (`[ld2450] ...`) must
not also change code other components build on: `esphome/core/`, the entity
platform components (`esphome/components/sensor/`, `esphome/components/text_sensor/`
including its `filter.*`, `binary_sensor/`, `number/`, ...), the buses
(`esphome/components/{i2c,spi,uart}/`), `network/`, `socket/`, the shared
constants (`esphome/components/const/`, `esphome/const.py`),
`esphome/automation.py`, `esphome/cpp_generator.py` or `esphome/config_validation.py`.
Flag it and ask for the shared change to move into its own PR, which lands first
and is reviewed by that code's owners; the component PR then builds on it. This
holds even when the shared change is small or only the component uses it today.
The exception is a shared change that must update several components in the same
PR so none of them breaks in between (a `[core]` or `[components]` PR that adds a
helper and moves its callers at once).
Not shared code: the component's own platform files (`esphome/components/<c>/sensor.py`,
`text_sensor/__init__.py`, ...), its new `USE_*` lines in `esphome/core/defines.h`,
and its `CODEOWNERS` entry.
## Memory and embedded constraints (highest value)
Heap allocation after `setup()` is treated as a reliability bug, not a
@@ -50,8 +28,8 @@ performance nit, because it fragments a small shared heap. Flag:
`StaticVector<T, N>` when a `push_back` API is needed) or fixed at runtime
init (use `FixedVector<T>`).
- Listener / child-entity registration lists stored as `std::vector`; these have
a compile-time-known count and should use `cg.slot_list()` plus
`SLOT_LIST` (or `cg.slot_counter()` plus `StaticVector`).
a compile-time-known count and should use `cg.slot_counter()` plus
`StaticVector`.
- `std::vector<uint8_t>` for a byte buffer that never grows: prefer
`std::unique_ptr<uint8_t[]>` or `std::array`.
- `std::map` / `std::set` / `std::unordered_map` for small datasets (1-16
@@ -61,12 +39,6 @@ performance nit, because it fragments a small shared heap. Flag:
literal already lives in flash).
- `std::string` / `std::to_string` / string-returning helpers on hot paths where
a buffer or view API exists.
- A `set_timeout` / `set_interval` / `defer` lambda whose captures exceed 8 bytes
on 32-bit or are not trivially copyable (`this` plus two 4-byte values, `this`
plus a member function pointer, a `std::string`, a `std::function`):
`std::function` then heap-allocates each time it is scheduled. Flag it on
retries, re-armed timeouts and hot-path `defer`; a `set_interval` set up once
in `setup()` is a single allocation. `[this]` plus one 4-byte value fits.
## C++ conventions
@@ -95,27 +67,6 @@ performance nit, because it fragments a small shared heap. Flag:
typed as `std::function`, so lightweight forwarders avoid a heap allocation.
- Two-space indent, `using` over `typedef`, wrap at 120 columns.
## Use the existing helper
New components often hand-write code a helper already covers. Ask for the
helper; `AGENTS.md` section 4 and the `component-codegen` skill have the detail.
| Seen in the PR | Ask for |
| --- | --- |
| `if (this->x_sensor_ != nullptr) this->x_sensor_->publish_state(v);` | `PUBLISH_STATE(this->x_sensor_, v);` (`esphome/core/entity_base.h`) |
| set warning / `return` / clear warning around a bus result | `if (!this->status_comm_result(ok)) return;` |
| hand-written `set_x_sensor()` plus `x_sensor_` member | `SUB_SENSOR(x)`, `SUB_BINARY_SENSOR`, `SUB_TEXT_SENSOR`, `SUB_SWITCH`, ... |
| `if CONF_X in config: s = await sensor.new_sensor(config[CONF_X])` plus setter | `sensors = sensor.sub_sensors(config)` then `await sensors(CONF_X, hub.set_x_sensor)` |
| hand-written `{"a": MyEnum.MY_ENUM_A, ...}` dict | `MyEnum.options("a", "b", prefix="MY_ENUM_")` |
| loops on `available()` / `read_byte()` | UART `read_available(on_byte)`, `discard_available()`, `LineReader<N>`, `FrameReader<N, HEADER...>` |
| hand-rolled CRC, checksum or bit loop | `crc8`, `crc16`, `xor_bytes`, `sum16_bytes`, `encode_uint16`, ... (`esphome/core/helpers.h`) |
| integer split into buffer bytes by hand (`buf[0] = v >> 8; buf[1] = v;`) | `put_be16`/`24`/`32`, `put_le16`, `put_le32` (`esphome/core/helpers.h`) |
| bare `mark_failed()`, or `ESP_LOGE` then `mark_failed()` | `this->mark_failed(LOG_STR("reason"))` or `LOG_STR(ESP_LOG_MSG_COMM_FAIL)` |
| button/switch/number/select C++ class that only calls the hub | `ApplyButton`, `ApplySwitch`, `ApplyNumber`, `ApplySelect` with `apply=` |
| action or condition class that only forwards to the parent | `register_apply_action` / `register_apply_condition` |
| enum-to-string `switch` returning literals | `PROGMEM_STRING_TABLE` with `get_log_str` / `get_progmem_str` |
| `if (x := config.get(CONF_X)) is not None: cg.add(var.set_x(x))` | `cg.add_optional(var.set_x, config.get(CONF_X))`, when the setter takes the value unchanged |
## Python conventions
- Type-annotate every new function signature (params and return), new dataclass
@@ -125,10 +76,6 @@ helper; `AGENTS.md` section 4 and the `component-codegen` skill have the detail.
`if (blah := config.get(CONF_BLAH)) is not None:`.
- Reuse existing validators from `config_validation.py` (`cv.rename_key`,
`cv.has_exactly_one_key`, etc.) via `cv.All(...)` instead of hand-rolling.
- A new or changed validator function that wraps, chooses or builds a schema
must be decorated with `@schema_extractor(...)` and handle `SCHEMA_EXTRACT`,
or `script/build_language_schema.py` silently drops the keys behind it (see
the `config-validation` skill).
- `esphome/const.py` is frozen: no new `CONF_` constants there. Define them in
the component's own `.py`, or in `esphome/components/const/__init__.py` when
shared. The same constant defined in three or more component files fails CI.
@@ -149,18 +96,6 @@ helper; `AGENTS.md` section 4 and the `component-codegen` skill have the detail.
- Config-only checks use the `validate.*.yaml` prefix; compiled checks use
`test.*.yaml`.
## Naming user-facing functions
Documented lambda methods, actions and config keys are public API, so a bad name
is hard to fix once released. Flag:
- A boolean where `true` means off (`display_off(true)`): name the positive
state, e.g. `set_power(bool on)`.
- A name that differs from a sibling component's name for the same operation.
Before a release, rename outright; after, follow the breaking-change policy
below.
## Breaking changes and public API
- Base classes under `esphome/core/` and documented config options are public
-276
View File
@@ -1,276 +0,0 @@
---
name: component-codegen
description: Write the Python side of an ESPHome component - __init__.py and platform files (sensor.py, switch.py, ...), DOMAIN and other metadata, to_code, hub child entities with sub_sensors and friends, pins and referenced components, hub-forwarding entities (ApplyButton, ApplySwitch), uart/i2c/spi constructor helpers, and CORE.data state. Use when creating a component or changing its code generation.
---
# Component code generation
Read https://developers.esphome.io/architecture/components/ for the component lifecycle and how a
component is registered. Schema rules and schema extraction are in the `config-validation` skill;
automations (`on_*`, actions, conditions) in the `automations` skill.
## Files
```
components/[component_name]/
├── __init__.py # Component configuration schema and code generation
├── [component].h # C++ header file (if needed)
├── [component].cpp # C++ implementation (if needed)
└── [platform]/ # Platform-specific implementations
├── __init__.py # Platform-specific configuration
├── [platform].h # Platform C++ header
└── [platform].cpp # Platform C++ implementation
```
## Metadata
- `DOMAIN`: required in every component's `__init__.py`, set to the component's own name as a plain string
(e.g. `DOMAIN = "my_component"`). Other code refers to the component through it, e.g.
`from esphome.components.my_component import DOMAIN`. Keep it in alphabetical order with the other
metadata constants. CI (`lint_component_domain`) fails without it.
- `DEPENDENCIES`: list of required components.
- `AUTO_LOAD`: components to automatically load. Not a way to put entities under the component's own key;
see "Entities of a hub" below.
- `CONFLICTS_WITH`: incompatible components.
- `CODEOWNERS`: GitHub usernames responsible for maintenance.
- `MULTI_CONF`: whether multiple instances are allowed.
## Basic pattern
```python
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_KEY, CONF_ID
DOMAIN = "my_component"
CONF_PARAM = "param" # A constant that does not yet exist in esphome/const.py
my_component_ns = cg.esphome_ns.namespace("my_component")
MyComponent = my_component_ns.class_("MyComponent", cg.Component)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(MyComponent),
cv.Required(CONF_KEY): cv.string,
cv.Optional(CONF_PARAM, default=42): cv.int_,
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add(var.set_key(config[CONF_KEY]))
cg.add(var.set_param(config[CONF_PARAM]))
```
```cpp
namespace esphome::my_component {
class MyComponent : public Component {
public:
void setup() override;
void loop() override;
void dump_config() override;
void set_key(const char *key) { this->key_ = StringRef(key); }
void set_param(int param) { this->param_ = param; }
protected:
StringRef key_;
int param_{0};
};
} // namespace esphome::my_component
```
When the setter takes the value unchanged, use `cg.add_optional(var.set_blah, config.get(CONF_BLAH))`; it
is not awaited, and it skips only `None`, so `0` and `False` are still set. Required, invariant
dependencies are constructor arguments to `cg.new_Pvariable()`, not setters.
## Entity platforms
**Sensor:**
```python
from esphome.components import sensor
CONFIG_SCHEMA = sensor.sensor_schema(MySensor).extend(
cv.polling_component_schema("60s")
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
```
**Binary sensor:**
```python
from esphome.components import binary_sensor
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend({...})
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
```
**Switch:**
```python
from esphome.components import switch
CONFIG_SCHEMA = switch.switch_schema().extend({...})
async def to_code(config):
var = await switch.new_switch(config)
```
## Entities of a hub
A new component's entities go in platform files (`sensor.py`, `binary_sensor.py`, ...) that take the hub's
id, never under the hub's own key with their platforms added to `AUTO_LOAD` to make that work. Auto loading
a platform because the C++ uses its type is fine. See
https://developers.esphome.io/architecture/components/#exposing-multiple-entities.
```yaml
# Bad - entities under the hub's key
my_hub:
connected:
name: Connected
# Good - the hub, then one platform entry that holds its entities
my_hub:
id: hub1
binary_sensor:
- platform: my_hub
my_hub_id: hub1 # optional with a single hub
connected:
name: Connected
```
**Optional child entities of a hub:** bind the config once with `sensor.sub_sensors(config)` (or
`sub_binary_sensors`, `sub_text_sensors`, `sub_buttons`, `sub_switches`, `sub_numbers`, `sub_selects` in
their domains), adding `parent=hub` for entities that derive from `Parented<T>`, then make one call per
key, even when there is only one. A call creates the entity only when its key is configured, passes it to
the setter and returns it (or `None`); extra arguments such as `min_value` or `options` go on the call.
Always name the setter explicitly on the object that owns it, never with `getattr` and an f-string, and
keep that variable short (`var` for the component itself, `hub` for one fetched with `cg.get_variable`) so
the calls fit on one line. Loops whose setter also takes an index, such as `set_gate_threshold(x, n)`, stay
as they are.
```python
# my_hub/sensor.py
async def to_code(config):
hub = await cg.get_variable(config[CONF_MY_HUB_ID])
sensors = sensor.sub_sensors(config)
await sensors(CONF_TEMPERATURE, hub.set_temperature_sensor)
await sensors(CONF_HUMIDITY, hub.set_humidity_sensor)
# my_hub/button.py
async def to_code(config):
hub = await cg.get_variable(config[CONF_MY_HUB_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_RESTART, hub.set_restart_button)
```
**Hub forwarding entities need no C++ class:** a button, switch, number or select that only calls its hub
uses `button.ApplyButton` (`switch.ApplySwitch`, `number.ApplyNumber`, `select.ApplySelect`) in its schema
and `apply=` on the `sub_*` call. The body is a call on the hub with `entity` and `state`, `value` or
`index`/`option` in scope; on a switch, number or select `publish="before"` or `"after"` publishes the
state, and `publish="on_success"` publishes only when the hub call returns true (a write the device can
refuse). `publish="momentary"` is only for legacy action switches (restart, factory reset): it publishes off
and runs the body only when turned on. Never use it for a new entity; an action is a button.
```python
switches = switch.sub_switches(config, parent=hub)
await switches(CONF_BLUETOOTH, None, apply="set_bluetooth(state)", publish="after")
```
Restore an owned or standalone switch in `setup()` with `sw->restore()`, or `restore(default)` to still
drive a state when the restore mode is disabled. A hub that applies its switches' restored states itself
reads `sw->get_initial_write_state()`, which already applies `inverted`.
**A hub that forwards data to its children:** when what each child does with the data is known at build time
(decode a register field, match a key or tag, publish a value), declare a `cg.HubFunction` once in the hub's
`__init__.py` and have each platform add one item per entity, built from codegen expressions. Code generation writes
one function per hub. Pass `define=` and put the hub's `HUB_PUBLISHER(<name>, args...)` (in a public section; it
ends on `public:`) and its call under that `#ifdef`; call the pointer only when it is not null. The children stay
plain entities, with no listener class or list. A child that lost a `Component` base keeps its dump lines through
a second hub function (`"dump"`, a `const char *` tag parameter, no define of its own) that the hub's
`dump_config()` calls inside the value function's `#ifdef`; every child adds to both.
**Entities that each watch a register field:** when every field (register, shift, mask, match) is known at
build time, use the rule above (see `bq25186`). A binary sensor tests its field value against an on-values
bitmap (`match`); a one-bit field reads the bit (simplified from bq25186's `_state_expression`):
```python
# hub __init__.py
STATUS_PUBLISHER = cg.HubFunction(
"status", # esphome__<hub>__status_fn, passed to HUB_PUBLISHER(status, ...)'s setter
cg.void,
[(BQ25186StatusRegisters.const_ref(), "status")],
define="USE_BQ25186_STATUS_PUBLISHER",
)
STATUS = STATUS_PUBLISHER.param("status")
# platform to_code, per configured entity
value = (STATUS[reg] >> shift) & mask
if mask != 0x01 or match != 0b10: # 0b10: a one-bit field that is on when set
value = (cg.MockObj(f"{match:#06b}") >> value) & 1
STATUS_PUBLISHER.add(hub, parent_ref(var).publish_state(value))
```
Store a field description per entity (a struct in a `SlotList` sized by `cg.slot_list`) only when the
field is chosen at run time, as in `sen6x`, where the status bit depends on the variant read in `setup()`.
Never a template per bit or a virtual listener base (a second vptr per entity).
## Other helpers
- **Pins and referenced components:** set them with `await cg.add_pin(var.set_cs_pin, config[CONF_CS_PIN])`
and `await cg.add_variable(var.set_bus, config[CONF_BUS_ID])`; both skip a `None` value, so pass
`config.get(KEY)` for an optional key, and return what they created. Use `cg.register_parented` for
`set_parent`.
- `uart.new_uart_component(config, *ctor_args)` (and `i2c.new_i2c_component`, `spi.new_spi_component`,
`modbus.new_modbus_client_component`, `ble_client.new_ble_node_component`) constructs, registers and
attaches in one call.
- A fixed buffer sized from the config is a file-scope static (BSS, not heap):
`buf = cg.static_buffer(config[CONF_ID], cg.uint8, size)`, named after its owner so `esphome analyze-memory`
counts it there; pass `buf` to the constructor.
A buffer that may live in PSRAM takes `psram=True`: PSRAM builds get a zeroed `psram_buffer<T>(size)` allocation
instead, so pass `buf` once and mark the component failed in `setup()` if it is nullptr. `align=4` emits
`alignas(4)`, so a word-aligned byte buffer stays `uint8`. `size` may be an expression such as `MyClass.static_("buffer_size")(n)`, which renders
`ns::MyClass::buffer_size(n)`.
- `display.add_writer(var, config)` sets the lambda.
- `MyEnum.options("on", prefix="MY_ENUM_")` builds an enum dict.
- `button.restart_button_schema(cls)` (and `factory_reset_`, `query_`) are button presets.
- `fv.get_declaring_config(id)` finds a hub's config in final validation.
## State during code generation
Use `CORE.data` for component state that needs to persist during configuration generation, namespaced
under the component's `DOMAIN` and held in a `@dataclass`. Avoid module-level mutable globals: they
persist between compilation runs if the host process (e.g. device-builder) doesn't fork/exec, whereas
`CORE.data` is cleared between runs.
```python
from dataclasses import dataclass, field
from esphome.core import CORE
DOMAIN = "my_component"
@dataclass
class MyComponentData:
feature_enabled: bool = False
item_count: int = 0
items: list[str] = field(default_factory=list)
def _get_data() -> MyComponentData:
if DOMAIN not in CORE.data:
CORE.data[DOMAIN] = MyComponentData()
return CORE.data[DOMAIN]
def request_feature() -> None:
_get_data().feature_enabled = True
```
Don't use flat keys such as `CORE.data["my_component_feature"] = True`. Some components use `TypedDict`
instead of a dataclass; both are acceptable.
-101
View File
@@ -1,101 +0,0 @@
---
name: component-tests
description: Write and run tests for ESPHome components - YAML build tests (test.*.yaml, validate.*.yaml, common.yaml) under tests/components, shared bus packages and CI test grouping, C++ gtest unit tests, and host integration tests including the uart_mock fixture. Use when adding or changing files under tests/, or when a code change needs test coverage.
---
# Component tests
## C++ unit tests
gtests live in `tests/components/<component>/*.cpp` and run with `script/cpp_unit_test.py <component>`; see
`tests/components/README.md`. Set the loop clock in a test with `LoopBlockingGuard{nullptr, nullptr,
now_ms}`; the runner resets it before every test.
## Integration tests
`tests/integration/` runs real firmware on the host. Serial components prove timeouts and recovery with the
`uart_mock` fixture (`tests/integration/test_uart_mock_*.py`). Its `responses` match on content every time
they see it; to answer a repeated request differently, use an `on_tx` lambda with a static counter and
`inject_to_rx_buffer` (see `uart_mock_ld2412_requery_after_giveup.yaml`).
## YAML build tests
```
tests/
├── test_build_components/
│ └── common/ # Shared bus packages (uart, i2c, spi, etc.)
│ ├── uart/ # UART at default baud rate
│ ├── uart_115200/ # UART at 115200 baud
│ ├── i2c/ # I2C bus
│ └── spi/ # SPI bus
└── components/[component]/
├── common.yaml # Component-only config (no bus definitions)
├── test.esp32-idf.yaml # config + compile
├── test.esp8266-ard.yaml # config + compile
├── test-variant.esp32-idf.yaml # variant test, config + compile
├── validate.esp32-idf.yaml # config-only (never compiled)
└── validate-legacy.esp32-idf.yaml # config-only variant
```
Run them with `script/test_build_components`. Use `-c <component>` to test specific components and
`-t <target>` for specific platforms.
- **Keep build-test variants few:** one `test.<platform>.yaml` per platform the code actually differs on.
A variant per board for platform-identical code only adds CI time.
- **Config-only test files (`validate.*.yaml`):** use this prefix when a YAML file only needs to exercise
schema/validation paths and does not need to be compiled. CI runs `validate.*.yaml` files with
`esphome config` only and skips them during compile. The grammar mirrors `test.*.yaml`:
- `validate.<platform>.yaml`: base config-only test
- `validate-<variant>.<platform>.yaml`: config-only variant
Use this for deprecated-syntax migration tests, schema edge cases, or platform-specific validation
branches where building firmware adds no signal. A component may have any mix of `test.*.yaml` and
`validate.*.yaml` files. Validate files never participate in bus grouping; each one runs as its own
`esphome config` invocation.
When a PR's only edits to a component are `validate.*.yaml` files (no source changes, no `test.*.yaml`
changes, and the component isn't pulled in as a dependency of another changed component), CI skips the
compile stage for that component and only runs config validation. This is decided in
`script/determine-jobs.py` via `_component_change_is_validate_only` and surfaced as the
`validate_only_components` output that the `test-build-components-split` job consumes.
## Grouping with packages
Components that use shared bus packages can be grouped together in CI to reduce build count. **Never define
buses (uart, i2c, spi, modbus) directly in test YAML files**; always use packages from
`test_build_components/common/`.
All includes in test files must go through dict-style `packages:` so that batch grouping works; the
grouping scripts only understand dict-style packages. Never use list-style packages
(`packages: [- !include ...]`) or top-level merge keys (`<<: !include common.yaml`). Bus packages are keyed
by the bus name; the component's `common.yaml` is keyed by the component name (e.g.
`cst328: !include common.yaml`):
```yaml
# test.esp32-idf.yaml - everything included via named packages
packages:
uart: !include ../../test_build_components/common/uart_115200/esp32-idf.yaml
my_component: !include common.yaml
```
```yaml
# common.yaml - component config only, NO bus definitions
my_component:
id: my_instance
sensor:
- platform: my_component
name: My Sensor
```
Components that define buses directly are flagged as "NEEDS MIGRATION" and cannot be grouped, increasing
CI build time. `!extend` and `!remove` in a `test.*.yaml` also make the component ungroupable; add a
standalone entity with its own id instead.
A test that needs a shared component in a particular state (`esp32_ble` security settings, an option that
PSRAM rejects) cannot be grouped: the merged block wins and the whole batch fails. Add the component to
`ISOLATED_COMPONENTS` in `script/analyze_component_buses.py`, or move the option to a `test-<variant>` file.
To verify that all components can be tested together without ID conflicts or configuration issues:
```bash
./script/test_component_grouping.py -e config --all
```
This tests all components in a single build to catch conflicts that might not appear when testing
components individually. Use `-e config` for fast configuration validation, or `-e compile` for full
compilation testing.
-124
View File
@@ -1,124 +0,0 @@
---
name: config-validation
description: Write or change ESPHome configuration validation - CONFIG_SCHEMA, cv.Schema, cv.typed_schema, custom validator functions, config keys and CONF_ constants, renamed or deprecated keys, and the language schema that script/build_language_schema.py extracts from them. Use whenever a change touches a component's schema or a validator in config_validation.py, automation.py or a component's .py files.
---
# Configuration validation
ESPHome validates YAML with `voluptuous` schemas built from `esphome/config_validation.py` (`cv`). The
same schemas are also walked by `script/build_language_schema.py`, which produces the JSON language schema
that editors and the dashboard use for completion and checking. A validation change is only finished when
both still work.
## Writing schemas
- **Type hints:** validators are typed like any other function: `def validate_x(config: ConfigType) ->
ConfigType:`, with `ConfigType` imported from `esphome.types`.
- **One schema per model:** when a component's options depend on a `model` key, use
`cv.typed_schema({...}, key=CONF_MODEL, default_type=...)` with each model's own keys and defaults, not
one schema plus a validator that rejects keys and fills defaults afterwards.
- **Reuse existing validators:** before writing a custom validator, check for an existing one in
`config_validation.py` and compose it in `cv.All(...)` rather than duplicating logic across components.
For example, rename a config key with `cv.rename_key(CONF_OLD, CONF_NEW, removed_in="2026.6.0")`, and
reject mutually-exclusive keys with `cv.has_at_most_one_key(...)` / `cv.has_exactly_one_key(...)`. See
how `api` composes `cv.has_exactly_one_key` + `cv.rename_key`.
- **Common validators:** `cv.int_`, `cv.float_`, `cv.string`, `cv.boolean`, `cv.int_range(min=0,
max=100)`, `cv.positive_int`, `cv.percentage`.
- **Complex validation:** `cv.All(cv.string, cv.Length(min=1, max=50))`, `cv.Any(cv.int_, cv.string)`.
- **Platform-specific:** `cv.only_on(["esp32", "esp8266"])`, `esp32.only_on_variant(...)`,
`cv.only_on_esp32`, `cv.only_on_esp8266`, `cv.only_on_rp2040`.
- **Framework-specific:** `cv.only_with_framework(...)`, `cv.only_with_arduino`. On the ESP32, Arduino is
built as a component of ESP-IDF, so an ESP-IDF API, sdkconfig option or version floor is there on both
frameworks: gate on `esp32.require_idf_version(cv.Version(5, 5, 3), "psram_dma")`, which checks the
platform and the ESP-IDF under either framework, as `spi`, `usb_host` and `wifi` do. Reserve
`cv.only_with_framework("esp-idf")` for a build that has been tried on Arduino and fails there, and write
the actual failure next to it (`sendspin`: arduino-esp32 below ESP-IDF 6.0 bundles a second libsodium,
and from 6.0 sendspin-cpp's enumerators collide with `Arduino.h` macros such as `DISPLAY`).
- **Schema extensions:**
```python
CONFIG_SCHEMA = cv.Schema({ ... })
.extend(cv.COMPONENT_SCHEMA)
.extend(uart.UART_DEVICE_SCHEMA)
.extend(i2c.i2c_device_schema(0x48))
.extend(spi.spi_device_schema(cs_pin_required=True))
```
- **Constants:** `esphome/const.py` is frozen; do not add new `CONF_` constants there. Define a
component-local constant in the component's own `.py`; for a constant shared by multiple components, add
it to `esphome/components/const/__init__.py`. CI (`lint_constants_usage`) fails if the same constant is
defined in three or more component files. Constants used in core files (those not under
`esphome/components`) may be added to `esphome/const.py` but will require adjustment to the CI check.
- **Renamed or removed keys:** see the `breaking-changes` skill for `cv.rename_key` and manual
deprecation warnings.
- **Config-only tests:** schema edge cases and deprecated-syntax migrations go in `validate.*.yaml` test
files (see the `component-tests` skill).
## Schema extraction
`script/build_language_schema.py` sets `esphome.schema_extractors.EnableSchemaExtraction = True` before it
imports any component, then walks every `CONFIG_SCHEMA` (and platform schema) recursively. It understands
`cv.Schema`, `cv.All`, `cv.Any`, dicts of `cv.Required` / `cv.Optional` keys, `.extend()`, `cv.ensure_list`,
`cv.typed_schema`, registries and the known `cv` validators. **A plain function it cannot see into**: a
custom validator that builds or picks a schema at validation time hides every key behind it, and the
dumper silently emits nothing for them. CI only runs the script with `--check`, which does not compare the
output, so a lost schema is not caught.
When a validator function wraps, chooses or builds a schema (rather than checking a single value), make it
visible to the dumper:
1. Decorate it with `@schema_extractor("<type>")` from `esphome.schema_extractors`.
2. At the top of the function, return the data for that type when it is called with `SCHEMA_EXTRACT`
instead of a config value. Compare with `is` (`value is SCHEMA_EXTRACT`); older code uses `==`.
```python
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
@schema_extractor("schema")
def _outgoing_connection_schema(config: ConfigType | None) -> ConfigType:
if config is SCHEMA_EXTRACT:
return _OUTGOING_CONNECTION_SCHEMA
if config is None:
config = {}
return _OUTGOING_CONNECTION_SCHEMA(config)
```
The type names the dumper accepts, and what `SCHEMA_EXTRACT` must return for each, are in the
`hidden_schemas` branch of `convert()` in `script/build_language_schema.py`. The common ones:
| Type | Return for `SCHEMA_EXTRACT` | Example |
|------|-----------------------------|---------|
| `"schema"` | the schema (or a representative one) to walk | `api` `_outgoing_connection_schema`, `restore_state_schema` in `esphome/core/entity_helpers.py`, `model_schema_extractor` in `esphome/components/mipi/__init__.py` |
| `"enum"` | the dict of options | `sensor_entity_category` in `esphome/components/sensor/__init__.py` |
| `"one_of"` | the list of options | `cv.one_of` |
| `"maybe"` | `(validator, key)` for a scalar shorthand | `cv.maybe_simple_value`, `maybe_conf` in `esphome/automation.py` |
| `"templatable"` | the inner validator | `cv.templatable` |
| `"automation"` | the automation schema | `automation.validate_automation` |
Points to watch:
- The dumper matches the function object by `repr`, so the decorated function must be the exact object
placed in the schema. In a factory that returns a new closure per call, decorate the inner function (as
`restore_state_schema` and `cv.maybe_simple_value` do), not the factory.
- The decorator only records anything when extraction is enabled, and that flag is set before imports, so
the decorator must run at import time (module level or inside a factory called at module level).
- A schema chosen per config value (for example by `model`) has no single answer: return a representative
schema, as `model_schema_extractor` does.
- Plain value checks (`cv.All(cv.string, my_check)`) need nothing: the dumper still sees the surrounding
types and keys.
- `cv.Schema`, `cv.typed_schema`, `cv.ensure_list` and the `cv` helpers are already handled; prefer
composing them over a custom function, which also avoids the extractor work.
### Checking the output
Build the language schema into a scratch directory and look at the component's JSON (it takes about ten
seconds):
```bash
python3 script/build_language_schema.py --output-path /tmp/schema
python3 -c "import json; print(json.dumps(json.load(open('/tmp/schema/my_component.json')), indent=1))" | less
```
Every key a user can write should appear under `config_vars` with a sensible `type`; compare against the
same output from `dev` when changing an existing schema. If the script prints `Unknown extracted schema
type` or raises, the decorator type or the value returned for `SCHEMA_EXTRACT` is wrong. Unit tests for
the dumper live in `tests/script/test_build_language_schema.py`.
-156
View File
@@ -1,156 +0,0 @@
---
name: display-test
description: Test an ESPHome display driver on a real panel with a camera. Use when a task asks to verify a display (LCD, e-paper, OLED, RLCD) on hardware, check orientation/rotation, partial updates, colours, contrast, or that text and shapes render correctly. Covers finding the USB port, flashing a test pattern, capturing the panel with any camera, and reading the photo.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
---
# Display testing with a camera
Point a camera at the panel to get visual evidence that a driver renders correctly. Any camera
and capture tool works; this skill covers the common ones. `$SKILL` below is this directory
(`.agents/skills/display-test`).
## Ask before using a camera
A camera can show people and rooms, not only the panel. Before the first capture, ask the user
for permission and for which camera to use. List the cameras the host has (the commands below
show how), name the one you intend to use, and wait for the user to confirm it. Do not pick a
camera yourself, and do not fall back to another camera if the chosen one fails; ask again.
The permission covers this session and the camera the user named. Ask again for a different
camera or in a new session. If the user declines, stop and report that the display was not
checked visually.
## Capturing a frame
Grab a still image, skipping the first few frames so auto-exposure and white balance settle.
Read the JPEG with the Read tool; the image is shown visually.
### macOS
The bundled Swift tool uses AVFoundation and avoids the frame-grabbing problems some USB
cameras have with other tools:
```bash
mkdir -p /tmp/camsnap /tmp/display-test
swiftc -O "$SKILL/scripts/camsnap.swift" -o /tmp/camsnap/camsnap
/tmp/camsnap/camsnap <camera-name-substring> /tmp/display-test/after.jpg 30
```
The camera argument is a case-insensitive substring of the name AVFoundation reports. If it does
not match, the tool lists the cameras it found, so a run with a name that matches nothing lists
the cameras without capturing. Use a substring that matches only the camera the user approved.
It creates the output directory if needed and reports encoding or write errors on stderr. Other
options include `ffmpeg` with `avfoundation` input, `imagesnap`, or Photo Booth's still capture.
### Linux
Use `ffmpeg` with the v4l2 input, `fswebcam`, or `v4l2-ctl`. With `ffmpeg`, `-ss 2` after the
input discards the first two seconds of frames while exposure settles:
```bash
mkdir -p /tmp/display-test
ffmpeg -f v4l2 -i /dev/video0 -ss 2 -frames:v 1 -y /tmp/display-test/after.jpg
# or
fswebcam -d /dev/video0 --skip 10 /tmp/display-test/after.jpg
```
List devices with `v4l2-ctl --list-devices`.
### Windows
Use `ffmpeg` with the DirectShow input (`-ss 2` skips the first frames, as on Linux), or any
camera application that can save a still image:
```powershell
mkdir C:\temp -Force | Out-Null
ffmpeg -f dshow -list_devices true -i dummy # find the device name
ffmpeg -f dshow -i video="<device name>" -ss 2 -frames:v 1 -y C:\temp\after.jpg
```
### Camera caveats
- The board may sit at an angle. Do not trust absolute pixel positions or aspect ratios from the
photo; judge orientation, ordering and approximate spacing, using the corner markers as
references.
- Reflections or a glossy cover can brighten one side. Capture again if a region is unclear.
- A moving pattern is caught at an arbitrary phase. Take several captures, or use a static marker
per position.
## Board and port
Find the port; names change on every replug:
```bash
python3 "$SKILL/../hardware-test/scripts/ports.py"
```
Native-USB ESP32-S3/C3/C6/H2 boards show up as `USB JTAG/serial debug unit` and need
`logger: hardware_uart: USB_SERIAL_JTAG`.
## Test pattern
Write a scratch config outside the checkout. Use one `name:` per board and include:
- a white background, a black border and a filled square at the centre, drawn in the first
update (full-window check and scale);
- a 60x20 bar near each corner, one bar per later update with `auto_clear_enabled: false`, so
each bar is written by its own partial window. The bars are wider than tall, which shows a
90 or 270 degree rotation; the corners exercise the window alignment;
- a 20x20 square under the left end of the top-left bar, drawn in the same update, which marks
the top-left corner and shows a 180 degree rotation or a mirrored image.
Use `Color::BLACK` and `Color::WHITE` in lambdas. Do not use the old `COLOR_OFF`/`COLOR_ON`
constants; black must mean black.
A ready template is in `$SKILL/templates/display-pattern.yaml`. Substitute the display platform,
pins and (for a driver with fonts) a font. The marker pattern needs no font.
## Build, flash, capture
Run from the worktree under test so `python -m esphome` imports the checkout, not an installed
copy:
```bash
cd <worktree>
python3 -c "import esphome; print(esphome.__file__)" # must print the worktree path
PYTHONUNBUFFERED=1 python3 -m esphome compile /tmp/display-test/display-pattern.yaml
PYTHONUNBUFFERED=1 python3 -m esphome upload /tmp/display-test/display-pattern.yaml \
--device /dev/cu.usbmodemXXXX
sleep 6 # boot plus a few update intervals
<capture command> /tmp/display-test/after.jpg
```
The device path differs by OS and host; use the path printed by `ports.py`. If the USB console
wedges during flashing (esptool `No serial data received`), replug the board and retry. A board
powered only by a battery may need the USB cable for flashing; the panel keeps its image when
power is removed, which is useful for checking that an image is bistable.
## What to check
1. **Orientation**: the extra square sits under the bar in the expected top-left corner. If it is
in another corner, the image is rotated or mirrored. Test `rotation:` values with the same
pattern. The logical width and height swap at 90 and
270 degrees, so the 60x20 corner bars should then appear taller than wide on the physical
panel.
2. **Coverage**: the border touches all four edges, with no dead rows or columns at the edges.
3. **Partial updates**: with `auto_clear_enabled: false`, draw one marker per update. Each should
appear exactly at its requested position with no smearing, offset or mirrored placement.
Include all four corners.
4. **Text and contrast**: sharp glyphs, correct polarity (black text on white, not inverted), no
ghosting from the previous frame.
5. **Speed**: if the driver logs transfer sizes, check that a full refresh and a partial window
take the expected times.
Record the build commit, board, config, and the captured image path when reporting results.
## When a partial update looks wrong
Take a marker-only capture before assuming the mapping is wrong: the camera's perspective makes
absolute positions deceptive. If markers land in mirrored positions, the controller's address
order (`MADCTL` MX/MY/MV) or the RAM block mapping is inverted for the window; verify the
full-frame path separately, then fix the window computation.
## Add findings
Add new capture tools, panel quirks, or recovery steps here so the next session starts ahead.
@@ -1,71 +0,0 @@
// camsnap <camera name substring> <output.jpg> [frames to skip]
// macOS only: grabs one frame from an AVFoundation camera after letting exposure settle.
// See SKILL.md for capture tools on other systems.
import AVFoundation
import AppKit
import CoreImage
let args = CommandLine.arguments
guard args.count >= 3 else {
FileHandle.standardError.write("usage: camsnap <camera name> <out.jpg> [skip]\n".data(using: .utf8)!)
exit(2)
}
let wanted = args[1].lowercased()
let outPath = args[2]
let skip = args.count > 3 ? Int(args[3]) ?? 30 : 30
let discovery = AVCaptureDevice.DiscoverySession(
deviceTypes: [.external, .builtInWideAngleCamera], mediaType: .video, position: .unspecified)
guard let device = discovery.devices.first(where: { $0.localizedName.lowercased().contains(wanted) }) else {
let names = discovery.devices.map { $0.localizedName }.joined(separator: ", ")
FileHandle.standardError.write("no camera matching '\(wanted)'; found: \(names)\n".data(using: .utf8)!)
exit(1)
}
final class Grabber: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
var seen = 0
let skip: Int
let out: String
init(skip: Int, out: String) { self.skip = skip; self.out = out }
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
seen += 1
guard seen > skip, let pixels = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
let image = CIImage(cvPixelBuffer: pixels)
let rep = NSBitmapImageRep(ciImage: image)
guard let jpeg = rep.representation(using: .jpeg, properties: [.compressionFactor: 0.9]) else {
FileHandle.standardError.write("failed to encode \(out) as JPEG\n".data(using: .utf8)!)
exit(1)
}
let url = URL(fileURLWithPath: out)
try? FileManager.default.createDirectory(
at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
do {
try jpeg.write(to: url)
} catch {
FileHandle.standardError.write("failed to write \(out): \(error)\n".data(using: .utf8)!)
exit(1)
}
print("saved \(out) after \(seen) frames")
exit(0)
}
}
let session = AVCaptureSession()
session.sessionPreset = .high
guard let input = try? AVCaptureDeviceInput(device: device), session.canAddInput(input) else {
FileHandle.standardError.write("cannot open \(device.localizedName)\n".data(using: .utf8)!)
exit(1)
}
session.addInput(input)
let output = AVCaptureVideoDataOutput()
output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
let grabber = Grabber(skip: skip, out: outPath)
output.setSampleBufferDelegate(grabber, queue: DispatchQueue(label: "camsnap"))
session.addOutput(output)
session.startRunning()
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
FileHandle.standardError.write("timed out waiting for frames\n".data(using: .utf8)!)
exit(1)
}
RunLoop.main.run()
@@ -1,43 +0,0 @@
# Display test pattern: corner markers, centre reference and partial-update markers.
# Replace the display platform and pins with the driver under test.
esphome:
name: display-pattern
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
logger:
hardware_uart: USB_SERIAL_JTAG
level: DEBUG
spi:
clk_pin: GPIO11
mosi_pin: GPIO12
display:
- platform: st7305
id: test_display
cs_pin: GPIO40
dc_pin: GPIO5
reset_pin: GPIO41
update_interval: 1s
auto_clear_enabled: false
lambda: |-
static int frame = 0;
if (frame == 0) {
it.fill(Color::WHITE);
it.rectangle(0, 0, it.get_width(), it.get_height(), Color::BLACK);
it.filled_rectangle(it.get_width() / 2 - 10, it.get_height() / 2 - 10, 20, 20, Color::BLACK);
} else if (frame == 1) {
it.filled_rectangle(20, 20, 60, 20, Color::BLACK);
it.filled_rectangle(20, 50, 20, 20, Color::BLACK);
} else if (frame == 2) {
it.filled_rectangle(20, it.get_height() - 40, 60, 20, Color::BLACK);
} else if (frame == 3) {
it.filled_rectangle(it.get_width() - 80, 20, 60, 20, Color::BLACK);
} else if (frame == 4) {
it.filled_rectangle(it.get_width() - 80, it.get_height() - 40, 60, 20, Color::BLACK);
}
frame++;
-175
View File
@@ -1,175 +0,0 @@
---
name: embedded-memory
description: Choose ESPHome C++ containers and storage that avoid heap use and fragmentation on microcontrollers - std::array, StaticVector with cg.slot_list/SLOT_LIST, FixedVector, std::unique_ptr byte buffers, StringRef, RAMAllocator, and what to avoid (std::vector growth, std::map, std::deque, std::string, new (std::nothrow)). Use when adding or changing C++ members, containers, buffers, strings or registration lists, or when reducing RAM or flash use.
---
# Memory on embedded targets
ESP devices run for months with small heaps shared between Wi-Fi, BLE, LWIP, and application code. Over
time, repeated allocations of different sizes fragment the heap. Failures happen when the largest
contiguous block shrinks, even if total free heap is still large. We have seen field crashes caused by
this.
**Heap allocation after `setup()` should be avoided unless absolutely unavoidable.** Every
allocation/deallocation cycle contributes to fragmentation. ESPHome treats runtime heap allocation as a
long-term reliability bug, not a performance issue. Helpers that hide allocation (`std::string`,
`std::to_string`, string-returning helpers) are being deprecated and replaced with buffer and view based
APIs.
## Container guidelines
1. **Compile-time-known sizes:** use `std::array` instead of `std::vector` when size is known at compile
time.
```cpp
// Bad - generates STL realloc code
std::vector<int> values;
// Good - no dynamic allocation
std::array<int, MAX_VALUES> values;
```
Use `cg.add_define("MAX_VALUES", count)` to set the size from Python configuration.
**For byte buffers:** avoid `std::vector<uint8_t>` unless the buffer needs to grow. Use
`std::unique_ptr<uint8_t[]>` instead. It does **not** provide bounds checking or iterator support like
`std::vector<uint8_t>`; use it only when you do not need these features.
```cpp
// Bad - STL overhead for simple byte buffer
std::vector<uint8_t> buffer;
buffer.resize(256);
// Good - minimal overhead, single allocation
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(256);
// Or if size is constant:
std::array<uint8_t, 256> buffer;
```
When the size comes from the config, declare it with `cg.static_buffer()` in `to_code` and pass the pointer
to the constructor, so it lands in BSS (see the `component-codegen` skill).
2. **Compile-time-known fixed sizes with vector-like API:** use `StaticVector` from
`esphome/core/helpers.h` for compile-time fixed size with a `push_back()` interface (no dynamic
allocation).
```cpp
// Bad - generates STL realloc code (_M_realloc_insert)
std::vector<ServiceRecord> services;
services.reserve(5); // Still includes reallocation machinery
// Good - compile-time fixed size, no dynamic allocation
StaticVector<ServiceRecord, MAX_SERVICES> services;
services.push_back(record1);
```
Use `cg.add_define("MAX_SERVICES", count)` to set the size from Python configuration.
**Listener and child-entity registration lists are the most common case, and the most commonly
missed.** When the hub only forwards data to its children and each child's handling is known at build
time, keep no list at all: use `cg.HubFunction` (see the component-codegen skill). When the hub must
store the children (it iterates them for other reasons, or picks fields at run time), a `register_*()`
method called once per child at code generation time has a count that is known at compile time, so it
should never be a `std::vector`. Declare the list with `SLOT_LIST` and register each child through the
call that `cg.slot_list()` returns, passing the hub's `DOMAIN`.
```python
# hub component's __init__.py
register_listener = cg.slot_list(
"MY_COMPONENT_LISTENER_COUNT", "register_listener", DOMAIN
)
# a platform of the hub
async def to_code(config: ConfigType) -> None:
...
hub = await cg.get_variable(config[CONF_MY_COMPONENT_ID])
cg.add(register_listener(hub, var))
```
```cpp
class MyComponent : public Component {
public:
SLOT_LIST(MyComponentListener, listeners_, register_listener, MY_COMPONENT_LISTENER_COUNT)
```
Do not put `#ifdef` around the macro or the loops over the list. Put `#if MY_COMPONENT_LISTENER_COUNT`
only around code that needs a child's own component (its header, its entity type).
If registering does more than append, write the method under `SLOT_LIST_REQUIRES(count)` and store into a
`[[no_unique_address]] SlotList<Entry, count>` member.
If the C++ side adds itself to the list, or the define gates more than the list, use `cg.slot_counter()`
keyed by hub (`_request_slot(str(hub))`) and put the storage behind `#ifdef`.
Request slots from `to_code`, not from a job that runs after `CoroPriority.FINAL`; a late request
raises rather than silently undercounting.
3. **Runtime-known sizes:** use `FixedVector` from `esphome/core/helpers.h` when the size is only known at
runtime initialization.
```cpp
// Bad - generates STL realloc code (_M_realloc_insert)
std::vector<TxtRecord> txt_records;
txt_records.reserve(5); // Still includes reallocation machinery
// Good - runtime size, single allocation, no reallocation machinery
FixedVector<TxtRecord> txt_records;
txt_records.init(record_count); // Initialize with exact size at runtime
```
This eliminates `_M_realloc_insert` and `_M_default_append` template instantiations (200-500 bytes per
instance), needs no upper bound, and is compatible with protobuf code generation when using
`[(fixed_vector) = true]`.
4. **Small datasets (1-16 elements):** use `std::vector` or `std::array` with simple structs instead of
`std::map`/`std::set`/`std::unordered_map`.
```cpp
// Bad - 2KB+ overhead for red-black tree/hash table
std::map<std::string, int> small_lookup;
std::unordered_map<int, std::string> tiny_map;
// Good - simple struct with linear search (std::vector is fine)
struct LookupEntry {
const char *key;
int value;
};
std::vector<LookupEntry> small_lookup = {
{"key1", 10},
{"key2", 20},
{"key3", 30},
};
// Or std::array if size is compile-time constant:
// std::array<LookupEntry, 3> small_lookup = {{ ... }};
```
Linear search on small datasets is often faster than hashing or tree overhead, but this depends on
lookup frequency; in hot paths the O(1) vs O(n) difference may still matter. It is the heavy containers
(`map`, `set`, `unordered_map`) that should be avoided for small datasets unless profiling shows
otherwise.
5. **Strings set once from configuration:** use `StringRef` (`esphome/core/string_ref.h`) rather than
`std::string`. Code generation passes a string literal that lives in flash for the life of the program,
so storing a `std::string` copies it onto the heap for nothing. `StringRef` is a non-owning pointer plus
length; it does not copy, and it must only ever refer to storage that outlives it (a string literal, or
a buffer owned elsewhere).
```cpp
// Bad - heap copy of a literal that is already in flash
void set_keys(std::string keys) { this->keys_ = std::move(keys); }
std::string keys_;
```
```cpp
// Good - no allocation
void set_keys(const char *keys) { this->keys_ = StringRef(keys); }
StringRef keys_;
```
6. **Avoid `std::deque`:** it allocates in 512-byte blocks regardless of element size, guaranteeing at
least 512 bytes of RAM usage immediately. This is a major source of crashes on memory-constrained
devices.
7. **Never use `new (std::nothrow)`:** on ESP-IDF exceptions are disabled, so a failed nothrow allocation
aborts instead of returning `nullptr`. Use `RAMAllocator` from `esphome/core/helpers.h`; CI rejects
`std::nothrow`.
8. **Detection:** look for these patterns in compiler output:
- Large code sections with STL symbols (vector, map, set)
- `alloc`, `realloc`, `dealloc` in symbol names
- `_M_realloc_insert`, `_M_default_append` (vector reallocation)
- Red-black tree code (`rb_tree`, `_Rb_tree`)
- Hash table infrastructure (`unordered_map`, `hash`)
Callback storage (`CallbackManager` vs `LazyCallbackManager`) and templated registration methods are
covered in the `automations` skill.
## Where to spend effort
Prioritize container optimization for core components (API, network, logger), widely used components
(mdns, wifi, ble), and components causing flash size complaints. Avoiding heap allocation after `setup()`
is always required regardless of component type; the priority list is about effort spent on container
migration (e.g. `std::vector` to `StaticVector`).
-197
View File
@@ -1,197 +0,0 @@
---
name: hardware-test
description: Test an ESPHome change on real boards over USB. Use this whenever a task asks to test, verify, reproduce, bench, A/B or soak a pull request, a branch or a crash on hardware, or mentions flashing, serial logs, esphome upload, a captive portal or fallback AP test, or results to post on a PR. Covers finding the serial ports, building from the right checkout, flashing each chip family (including the LibreTiny kits that stock tools cannot flash), bounded log capture, proven test flows and how to report results.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
---
# Hardware testing
The goal of a hardware test is evidence a reviewer can trust: which build ran on which board, what was
driven, what the logs show, and the same flow on a `dev` build when a quirk could be pre-existing.
`$SKILL` below is this directory (`.agents/skills/hardware-test`).
## Ground rules
1. **Serial ports cannot be shared.** One bounded capture per port, stopped before any flash on that
port, never an open-ended `esphome logs`. Stop a capture with `pkill -f "[s]erial_capture.py <port> "`,
naming the port so a capture on another board survives; the bracket keeps the pattern from matching
the shell that runs it. When more than one agent session shares the bench, run a copy of the script
under a session-specific name (`cap<topic>.py`) so another session's `pkill` cannot take your capture
down. Never run `esphome logs` in a `while true` loop: the loop respawns it and holds the port.
2. **Credentials stay local.** Put a `secrets.yaml` next to the scratch configs and reference it with
`!secret`. A copy of a device's own config keeps using the secrets file next to that config: two
checkouts can hold different networks, and the wrong one leaves the device unreachable after the OTA. Never paste a config with credentials into a PR, never commit scratch configs or logs.
3. **Build from the tree under test.** `python -m esphome` puts the current directory first on
`sys.path`, so run it with the checkout or worktree as the working directory and pass the yaml by
its absolute path. A venv `esphome` entry point may import an installed snapshot instead of the
checkout. Confirm with `python -c 'import esphome; print(esphome.__file__)'`, and for an A/B grep
the build's `src/` for the change before trusting any number. Tool calls sent together share one
shell, so a `cd` in one can land another's compile in the wrong tree: pass `PYTHONPATH=<worktree>` on
every compile and upload command and print `esphome.__file__` into the compile log.
4. **PR build and baseline build get different `name:` values.** Builds share
`.esphome/build/<name>`, so the same name means `esphome upload` can flash the wrong binary. Saved
Wi-Fi credentials are keyed by the config hash when the config has `networks:`, so a test that must
start unprovisioned gets a fresh name every run. A config with `ap:` only and no `networks:` uses one
fixed key shared by every such config on the board, so a new name does not help there: wipe once at
boot with an `on_boot` lambda that resets the preferences and saves a marker key
(`templates/dut-ap-only-wipe-once-bk72xx.yaml`).
5. **Flash and RAM deltas are measured against the PR's merge base** (`git merge-base origin/dev HEAD`
checked out in a throwaway worktree), with the baseline commit named in the table. When a delta
looks odd, diff symbol sizes (`nm -S -C --size-sort` from the matching toolchain) before quoting it.
When a change moves storage between the heap and static RAM, the static number alone misleads: also log
the free heap at the end of setup (`on_boot` at priority -100) over three boots of each build and report
the total in use (static RAM plus heap used).
6. **Prove a quirk is pre-existing before blaming the PR:** run the identical flow on a `dev` build in
the same session and say so in the results.
7. **Pipe safely.** Set `PYTHONUNBUFFERED=1` on any `esphome run` or `esphome logs` whose output is
piped, or lines land minutes late. Bound every long command with `timeout` (coreutils) or
`perl -e 'alarm shift; exec @ARGV' <seconds> <command>` on macOS without it. Save an exit code with `rc=$?`
right after the command: in `echo "$(date +%T) rc=$?"` the command substitution runs first and `$?` reads 0.
## Workflow
1. **Find the boards:** `python $SKILL/scripts/ports.py` (any Python with pyserial, for example the
ESPHome venv). Port names follow the USB hub port and change on every replug, so never reuse a name
from an earlier session. CH340 adapters (D1 mini, BW15 kit, BK7238, CB3S) all look the same; tell
them apart with a 10 s capture using `serial_capture.py --reset` (ESP8266 prints its ROM banner at
74880 baud, LibreTiny boards print `[LT]` and ESPHome lines, BK7238 prints its bootloader version).
`ports.py --wait 2e8a` blocks until a Pico re-enumerates.
2. **Make a scratch directory** outside the checkout, with `secrets.yaml` and the templates you need.
One yaml per board per variant, file name equal to `name:`.
3. **Compile** in the right tree:
`(cd <worktree> && PYTHONUNBUFFERED=1 timeout 1500 python -m esphome compile <abs yaml> > <name>-compile.log 2>&1)`.
Keep the RAM and flash lines at the end. Two ESP-IDF or two LibreTiny builds at the same time race
over tool caches; run them one at a time.
4. **Flash** per chip family (table below). Stop the capture on that port first.
5. **Capture** with `serial_capture.py PORT SECONDS OUT` in the background, then poll the file with
`grep` in an `until ... sleep 2` loop with a cap. USB CDC boards (Pico, nRF52, native USB ESP32)
drop the port on reboot; the script reopens it until its deadline.
6. **Drive** the test: a second board running a client config, `curl`, an aioesphomeapi script that
presses a template button and subscribes to logs, MQTT publishes, or `interval:` and `on_boot:`
automations in the config itself.
7. **Analyze** with `grep -a -c` counts over the capture and keep an `-events.txt` extract of the lines
that matter. Decode crashes with the platform's `addr2line` (see `reference/boards.md`).
8. **Report** on the PR. Every result comment starts with this two-line GitHub alert, then a blank line:
```
> [!NOTE]
> Automated testing results
```
Then one short sentence saying what was tested (builds and SHAs, board, what was driven), a results table
(build SHA, board and framework, what was driven, counts, result, plus the `dev` control row), short bullets
for the findings, and the setup and exact flow in a collapsed `<details>` block. Answer any question asked on
the PR directly in the comment. No credentials, SSIDs, IP addresses, port names or other bench details.
## Flashing by chip family
| Board | Flash | Log |
|---|---|---|
| ESP8266 D1 mini (CH340) | `python -m esphome upload <yaml> --device <port>` | `serial_capture.py` at 115200; `esphome logs` on some CH340s emits garbage after the RTS reset. A failed esptool write can wedge the adapter until the board is replugged. `esptool erase_flash` before a test that needs an unprovisioned device: the preference sector survives a reflash |
| ESP32 devkit (CP2102 or CH340) | `esphome upload --device <port>`, ESP-IDF or Arduino | `serial_capture.py`. Default Wi-Fi light sleep delays API driven actions by seconds; judge timing from device logs. `power_save_mode: none` for OTA overlap tests |
| ESP32-S3, C3, C6, H2 native USB | `esphome upload --device /dev/cu.usbmodem*` | `logger: hardware_uart: USB_SERIAL_JTAG`. The USB console can wedge when the app takes over the console (0 bytes, esptool `No serial data received`); replug, or watch through `esphome logs --device <name>.local` |
| Pico W / Pico 2 W | `esphome upload --device <port>` (1200 baud touch); first flash ever via BOOTSEL and `--device /Volumes/RPI-RP2` or `RP2350` | port re-enumerates after upload: `ports.py --wait 2e8a` then capture |
| BW15 kit (RTL8720CF, rtl87xx) | `~/.platformio/penv/.libretiny/bin/python $SKILL/scripts/flash_rtl87xx_kit.py flash write -d <port> <build>/.pioenvs/<name>/*.uf2`. Plain `esphome upload` and plain ltchiptool time out because opening the port asserts DTR/RTS and holds the chip in reset | `serial_capture.py --released`, never `esphome logs` |
| BW12 and other AmebaZ modules (RTL8710BX, rtl87xx) on a plain USB-UART | `~/.platformio/penv/.libretiny/bin/python -m ltchiptool flash write -B 115200 -b 115200 -t 120 -d <port> <uf2>`, started first, then strap by hand: CEN to GND, TX2 to GND, release CEN, release TX2. Without `-B 115200` the system data read at 1.5 Mbaud fails on CH340s (`Data read error at 0x9000`) and nothing is written. A 1 MB image takes about 80 s. A development board with DTR and RTS wired to CEN and the download pin needs no strap | `serial_capture.py`; a reset pulse does not reach CEN on a plain adapter, so a capture starts mid-run |
| BK7238 / CB3S (bk72xx, RTS on CEN) | `~/.platformio/penv/.libretiny/bin/python $SKILL/scripts/flash_bk72xx.py flash write -d <port> <uf2>` (about 75 s) | logs are on UART2 by default; `logger: hardware_uart: UART1` puts them on the flashing adapter. `serial_capture.py --reset` gives a chip-enable reset; a plain open may or may not reset it, check for the bootloader banner |
| LN882H | ltchiptool forces 1 Mbaud for writes; weak adapters need `LN882H_YM_BAUDRATE` patched to 115200 in the penv's `ln882htool.py`; short BOOT to GND while the tool connects | OTA after the first flash |
| nRF52840 Dongle (PCA10059) | Nordic `nrfutil nrf5sdk-tools dfu usb-serial` on the bootloader port, or `dfu: true` in the config so the 1200 baud touch pin-resets into the bootloader; adafruit-nrfutil is refused | app has two CDC ports, ESPHome log on the second |
| Adafruit-style nRF52 (UF2 bootloader) | `UF2BOOT` volume or adafruit-nrfutil; `dfu: true` works through GPREGRET | single CDC port |
| Any reachable device | `esphome upload <yaml> --device <ip or name.local>`; `--file <bin>` for a prebuilt image | `esphome logs --device <ip>` bounded with `timeout` |
ESP-IDF OTA image: `.esphome/build/<name>/build/firmware.ota.bin`. LibreTiny OTA port is 8892.
## Scripts in `$SKILL/scripts`
- `ports.py`: list ports with VID:PID, product, serial and a board guess; `--wait VID[:PID]`,
`--product NAME`, `--serial SN` (one specific board, whatever path it comes back under) and
`--serial-of PORT` (the serial number behind a path).
- `serial_capture.py PORT SECONDS OUT [--baud] [--released] [--reset] [--append] [--ms]`: bounded timestamped
capture (`--ms` adds milliseconds for timing work), ANSI stripped, `LOG_SECRET` text written as `<secret>`, reopens a vanished port, exits at the
deadline. OUT is truncated unless `--append` is given, so counts over it cover one run.
- `flash_rtl87xx_kit.py`: ltchiptool wrapper for the BW15 kit whose CH340 drives CEN (RTS) and the boot
strap (DTR). `flash read` needs the family `realtek-ambz2`; `flash write` does not.
- `flash_bk72xx.py`: ltchiptool wrapper for BK72xx boards whose RTS drives CEN. It misses the link now
and then; retry up to three times.
- `api_button.py HOST KEY list|press NAME [...]`: list a device's template buttons or press them over the API; the
recipes drive their test configs with it.
- `apiconn.py`: `connect(host, tries)` (API connect and login with retries, `API_KEY` from the env) and `log_text()`
(an API log line without ANSI codes), imported by the newer API drivers.
- `wifisave_hammer.sh KIND DUT_PORT DUT_YAML DUT_TREE CLIENT_PORT CLIENT_YAML CLIENT_TREE [SETTLE]`:
the fallback AP plus captive portal hammer end to end (compile, flash, capture, counts) with the
templates below. KIND is `esp`, `pico`, `bw15` or `bk`. It ends with `RESULT PASS` (exit 0),
`RESULT FAIL` (exit 3: a crash, a reboot after the AP came up, or the device never joined the network),
`RESULT INVALID`
(exit 2: a precondition was missed, the stimulus was insufficient, or a capture did not last the run)
or exits 1 when a build, flash or port step failed.
Per-topic scripts, each described in the matching `reference/recipes/<component>.md`: `online_image/`
(server with prefixed misbehaviour cases, PNG, JPEG, BMP and QOI generators, API drivers, first pass timer), `zwave_proxy/` (checksum verifier, device info), `usb_cdc_acm/`
(host driver, Zephyr driver probe), `rtsp_server/` (protocol client, raw rate reader, measurement set,
API image grab), `cse7766/` (API observer with ping), `zephyr_coredump/` (reader flow, decode with the
Zephyr tools), `libretiny_prefs/` (rtc preference harness header), `libretiny_crash/` (BK72xx crash probe header,
capture decoder, RTL8720C ROM dump versus report matcher), `api_outgoing/` (wake cycle and Wi-Fi drop timing readers), `ld2450/` (zone number driver, loopback harness driver with number and binary sensor states and TX frame summarizer, frame stream harness with presence hold and link loss drivers, BT MAC driver), `api/` (raw plaintext native API client for user defined actions, store_yaml recovery client over Noise or plaintext), `http_request/` (update manifest server, update state driver, request test server, action case driver, concurrency, reboot, update check and OTA drivers, `ota_auth/` OTA request cases with basic auth), `modem/` (button and sensor driver over the plaintext API, also used for the BLE MIDI boards), `dfrobot_sen0395/` (API driver and case runner), `homeassistant_light/` (direct bulb driver, held-report case driver), `usb_audio/` (URL player), `speaker_media_player/` (API player driver, pipeline task case runner), `web_server/` (SSE client, request mix, SSE and HTTPD case runners), `mqtt/` (`ha_discovery/`, `disable/`, `retained_burst/` and `reconnect/` runners; broker config with TLS, client-certificate and WebSocket listeners, test CA with server and client certificates, transport case runner, flash-and-drive runner, CLI TLS check without a board, MAC suffix runner with per-variant configs for two boards, `shutdown/` shutdown message runner and matcher), `udp/` (datagram recorder, `udp.write` payload checker and case driver), `entity_icons/` (icon and device class readback over the API, MQTT discovery, web_server and dump_config, with a comparer), `uart_sim/` (API driver and flash, capture and drive runner for the simulated UART sensors), `remote_base/` (loopback runner and API log decoder per sent frame), `xiaomi_ble/` (frame and header generator with the expected counts, injecting, advertising and receiving configs, counter and runner), `ble_terminate/` (proxy and peer configs, connect and disconnect driver, peer disconnect matcher, runner), `i2c_slave/` (D1 mini slave and BK7238 master configs), `wpa3_ap/` (PMF AP with join and leave logging, BK7238 and CB3S DUTs, runner and summary), `wisp_ap/` (WISP upstream with AP buttons, WISP and ALWAYS_ON DUTs, client, runner and per phase summary), `wifi_restart/` (WPA3 mixed WISP upstream, static IP DUTs with syslog, runner and summary), `ota_timing/` (OTA upload timer with deflate, raw and TCP modes, API build check, A/B runner and median summary, `inflate_bench/` on-device inflate benchmark with stream generator, configs and syslog runner), `gpio_hold/` (ISR pin hold self test with ESP32 and S3 configs), `ble_event_inject/` (GAP and GATTC event injector header and proxy package), `light_sleep_wake/` (LEDC wave and edge timer for light sleep wakeup on a C3, external wave generator and per-call edge detail probe for peripheral power-down on the P4), `manual_ip/` (station and AP manual IP configs, DNS probe and runners), `web_handlers/` (late handler, web_server, captive_portal and prometheus variants, web OTA runner), `bk72xx_flash/` (flash readback with retries, per partition diff of two dumps), `ble_server_security/` (secure GATT server and pairing client configs, driver, summary and runner), `prometheus/` (datetime metrics configs and driver), `zephyr_ble_server/` (nRF52 server, looping ESP32 client and UF2 flash and count runner), `ble_adv_triggers/` (advertiser with six raw frames, ESP32 and BK72xx receivers with eleven triggers, runner and checker), `sun/` (longitude sweep package, runner and checker), `sensor_filters/` (every filter shape with a fixed input sequence, per-board packages and runner), `led_driver_sniff/` (SPI slave capture header with selftest, config generator, window comparer and runner), `hub_input_sim/` (keypad, wiegand and rdm6300 simulation on a D1 mini, API log runner), `value_range/` (on_value_range sequence with a restart, runner), `ezo_fake_bus/` (fake EZO I2C bus and step config, runner), `twai_self/` (TWAI self-reception header, on_frame config and counter runner), `ota_automations/` (OTA automation package for both OTA platforms, four case runner, repeated web upload runner and per case summary), `output_button/` (pad edge timer header, button package and runner), `homeassistant_button/` (raw plaintext API client for action calls and wizard inputs, package and runner), `uart_button/` (UART0 loopback package, API driver with TX and RX counts, runner), `interval/` (plain and delayed interval package, timing summary and runner), `smp_udp_ota/` (SMP reset fault injector, OTA runner, per mode result check, MCUboot swap limit, running image check and slot blanking UF2, Thread device config), `ld2420_sim/` (fake LD2420 answering the hub's commands on a UART0 loopback, API state recorder, two-build comparer and runner), `nrf52_tcp_probe/` (TCP and UDP socket probe config, build and log check, API check over Thread), `rs485_frame/` (simulated DLE/STX/ETX bus device, frame and gate cases, runner), `hx711/` (fake HXLine truncated
## Templates in `$SKILL/templates`
- `dut-fallback-ap.yaml` (package): a device that never finds its network, falls back to its AP and
serves the captive portal. `example-dut.yaml` is the per-run file with the platform block.
- `client-wifisave.yaml` (package): joins that AP, posts N bogus `/wifisave` requests, then the real
credentials from `!secret`. `example-client.yaml` is the per-run file. `bogus_saves: "1"` gives a
plain provisioning check.
- Per-topic device configs, each described in `reference/recipes/<component>.md`: `online-image-dut.yaml`,
`usb-cdc-acm-dongle-dut.yaml`, `nrf52-preferences-dut.yaml`, `rtsp-waveshare-s3-eth-dut.yaml`,
`waveshare-s3-eth-camdiag.yaml`, `s31-cse7766-dut.yaml`, `nrf52-coredump-crash-dut.yaml`,
`bk72xx-rtc-prefs-dut.yaml`, `bk72xx-crash-probe-dut.yaml`, `dut-ap-only-wipe-once-bk72xx.yaml`,
`homeassistant-light-dut.yaml`, `deep-sleep-outgoing-dut.yaml`, `outgoing-wifi-drop-dut.yaml`,
`globals-storage-dut.yaml`, `usb-audio-waveshare-s3-eth-dut.yaml`, `usb-audio-sendspin-s3-eth-dut.yaml`,
`cast-pro-1-sendspin-control.yaml`, `aux-2-preprod-stock-dut.yaml`, `aux-2-preprod-usb-audio-dut.yaml`,
`dfrobot-sen0395-dut.yaml`, `aux-2-preprod-speaker-player-dut.yaml`, `web-server-sse-dut.yaml`,
`mqtt-transport-dut.yaml`, `mqtt-tls-dut.yaml`, `udp-write-dut.yaml`, `entity-icon-dut.yaml`,
`online-image-s3-eth-dut.yaml`,
and the directories `store_yaml/` (package with secrets one directory up, per-board files),
`http_request_update/` (manifest URL setter shapes, per-board files), `modem/` (modem only and modem plus
Wi-Fi boot checks), `ble_midi/` (fake BLE MIDI instrument and the client), `http_request_action/` (request
action package with per-board files and an OTA flash variant), `led_wire/` (DUT config and header that reads the
LED strip pads back with RMT RX and an SPI slave), `uart_sim/` (simulator header, common package, per-build parts and run files) and `remote_base/` (common
package, transmit script, per-board templates and the ESP8266 software sender), `i2c_fake/` (fake I2C device
headers with their test configs, see `fake_i2c.md`).
- `microphone_http_stream/`: base config, fake counter and USB microphone variants and the multi-reader client,
described in `reference/recipes/microphone_http_stream.md`.
## When the PR keeps moving
Record every head in the stack (`gh pr view N --json headRefOid`), build, and recheck before flashing; if anything
moved, wait five minutes and check again so the test runs on a settled head. When a head moved only by merging dev,
compare the PR's own diff (`git diff $(git merge-base OLD origin/dev) OLD` against the same for NEW); if it is
identical and the dev commits do not touch the code under test, earlier results still describe it, but rebuild so the
comment quotes the exact commits. Fetch `origin dev` before computing a merge base.
## When something looks wrong
- A capture stopped early or a line is missing: check the timestamps before trusting it.
- A script that pipes into `tee` never ends although its work is done: a background command written as
`(cd dir && server & echo $!)` backgrounds the whole `cd && server` list, so a shell stays behind holding the
pipe open and `$!` is that shell, not the server. Write `(cd dir && exec server > out 2>&1 < /dev/null) &`.
- The client never joins the AP: another board may still run an AP with the same SSID, or the device
booted with saved credentials because the name was reused. One AP device at a time on the bench.
- Builds come out byte-identical between branches: the wrong tree was imported (rule 3). The reverse
too: two binaries that differ only in the build timestamp and in `__LINE__` values of log calls below
the changed code are the same build; map the offsets with `objdump -h` and `addr2line` first.
- A boot the host cannot capture (a power cut, an OTA-only board): keep the boot report in a flash
preference and repeat it in a periodic alive line, as `scripts/libretiny_prefs/ltprefs.hpp` does.
- Multicast from the host never arrives on some access points: test it device to device. Broadcast
is lossy under Wi-Fi power save, unicast is not. Throttle UDP floods to a fixed packet rate.
- The merge base comes from a freshly fetched `origin/dev`; a stale local `dev` puts dependency bumps into the
PR diff and builds the control from the wrong commit.
- A `.local` name can stop resolving in the middle of a run; keep the address from the boot log and drive by it.
- Never point `framework: source:` at a local `file://` copy of LibreTiny to try a patch: PlatformIO installs it over
the shared `~/.platformio/platforms/libretiny`, so every later build on the machine uses the patched copy. Patch
through the ESPHome side (a linker `-Wl,-wrap,<symbol>` or a define) instead, and if it happened, restore the
directory from a clean copy of the same release.
- `wc -l` pads its count on macOS, so `tail -n +$n0` needs `$((n0+0))` or an arithmetic expansion.
- `api:` reboots a board after 15 min without a client: `reboot_timeout: 0s` on `api:` and `mqtt:` for
soak tests.
`reference/boards.md` has per-chip facts and crash decoding; `reference/recipes/` has the proven
flows. Add new findings there.
@@ -1,416 +0,0 @@
# Board facts
Ports are not listed on purpose: they follow the USB hub port and change on every replug. Run
`scripts/ports.py`.
## ESP8266 (D1 mini, NodeMCU, CH340 or CP2102)
- Opening the port usually resets the board through DTR, but not always; `serial_capture.py --reset`
pulses RTS to capture from boot. 74880 baud shows the ROM boot messages (`rst cause`, `boot mode`).
- UART0 can be looped back onto itself (`USC0(0) |= (1 << UCLBE)` in an `on_boot` lambda) so a UART
component is testable without its device: frames written with `uart.write` arrive on RX. Log over the
API with `logger: baud_rate: 0`, since the serial port carries the component's bytes.
- `esphome logs` on some CH340s emits thousands of duplicated garbage lines right after the RTS reset;
a plain pyserial capture at 115200 is reliable.
- A failed esptool write can wedge the adapter (`termios` error 22, or an open that hangs) until replug.
- The preference sector survives a reflash: a provisioned API key or saved Wi-Fi credentials stay
active. `esptool erase_flash` gives a clean device.
- `Panic core_esp8266_main.cpp:191 __yield` with `ctx: sys` means a yield from lwIP context (a web
handler, an lwIP callback). Decode stacks with
`xtensa-lx106-elf-addr2line -e <build>/.pioenvs/<name>/firmware.elf -f -C -i <addr...>` from the
toolchain under `~/.platformio/packages/toolchain-xtensa/bin/` (PlatformIO builds) or the ESPHome
cache directory (native toolchain builds).
- Constant data lives in RAM unless marked `PROGMEM`; with 80 KB of RAM a few hundred bytes are worth a
row in the PR.
- AsyncMqttClient drops inbound topics over 128 characters; topics of 255 or more wrap a counter and
stall the link until the broker drops TCP.
## ESP32 classic devkit
- Takes ESP-IDF and Arduino. Default Wi-Fi light sleep delays API driven actions by up to 6 s; judge
timings from device logs, not from the host. `power_save_mode: none` for OTA overlap tests (an IDF web
upload of 739 KB took 107 s with power save and 45 s without).
- Receives only a few percent of IPv6 multicast on some access points with power save on; a raw lwIP
socket loses the same, so that is the AP or driver, not a PR.
- Decode with `xtensa-esp32-elf-addr2line` from the IDF tools directory against
`<build>/.pioenvs/<name>/firmware.elf` (PlatformIO) or `<build>/build/<name>.elf` (IDF native).
- Clean reboot between runs with the capture stopped: `esptool --after hard_reset chip_id`.
- Trigger a forced crash only after the app is marked valid (45 s after boot is plenty), never on an
image still pending OTA rollback.
- Signed OTA testing: build with `esp32.framework.advanced.signed_ota_verification.verification_keys`
under a different name, sign with `python -m espsecure sign_data --version 2 --keyfile
tests/components/esp32/dummy_signing_key.pem`, upload with `esphome upload --file`. The verifier
refuses unsigned images afterwards, so restore with a signed plain build.
- An ESP32 whose bootloader has no app rollback is protected only by `safe_mode` after a bad OTA. Before sending a
change to such a device that nobody can reach by hand, boot the same code on a devkit first and keep a fallback
image of the merge base built.
## ESP32-S3, C3, C6, H2 with native USB
- `/dev/cu.usbmodem*`, esptool works, `logger: hardware_uart: USB_SERIAL_JTAG`.
- The USB console can die at the moment the app takes over the console during a reboot (log stops after
`Disabling RNG early entropy source`, then 0 bytes, esptool reports `No serial data received`). Only a
USB replug fixes it. Fallback: `esphome logs --device <name>.local` (API log stream, which drops lines
while Wi-Fi is off).
- The ESP32-P4 before silicon revision 3 is bricked by rev3-only firmware (boot loop at bootloader entry). The
Waveshare ESP32-P4-WIFI6 rev1.3 board is such pre-rev3 silicon.
- S3, C3 and C6 all enumerate as `303a:1001`; confirm the chip with `esptool --port <port> chip_id` before flashing.
- ESP32-C6 test configs: set `wifi: power_save_mode: none`. With the default light sleep, API commands and state
updates arrived seconds late and a 1.2 s step check failed at random on base and PR alike (esphome#22339).
- An S3 on Arduino with `logger: hardware_uart: USB_CDC` enumerates as TinyUSB CDC (`303a:0009`). If that build
crash loops (a FastLED plus NeoPixelBus build aborts in `check_rmt_legacy_driver_conflict`), esptool cannot catch
the port: hold BOOT, tap RST, keep BOOT held about 2 s, then flash with `--before no-reset`. A plain RTS hard reset
leaves it in the loader on USB JTAG; `--after watchdog-reset` boots the app. Keep Arduino LED tests on the classic
ESP32.
- A board left in the ROM bootloader after an upload (BOOT held, or the USB JTAG reset landing in download mode
again) starts its app without a replug through `esptool --port <port> --after watchdog-reset chip-id`; flash a
minimal Wi-Fi plus API image first when recovering from a crash-looping one.
## RP2040 / RP2350 (Pico W, Pico 2 W)
- The CDC port re-enumerates after every reboot and after `esphome upload` (1200 baud touch). Re-detect
with `ports.py --wait 2e8a` before capturing; `serial_capture.py` reopens on its own if the port
vanishes mid-capture.
- First flash ever: BOOTSEL, then `esphome upload --device /Volumes/RPI-RP2` (or `RP2350`).
- arduino-pico creates the lwIP netif in `WiFi.begin()`, so any IGMP join during component setup fails;
joins must wait for `network::is_connected()`.
- Parallel Pico builds race on package extraction after a PlatformIO package wipe; one at a time.
- An RTS pulse from pyserial does not reset the board; reboot with `App.safe_reboot()` or the touch.
- LEAmDNS re-enters `update()` from the receive handler on the Pico too (measured), so an ESP8266-only guard does
not cover it.
- An image with only `ota: platform: web_server`, built from a tree without the fix for uploads of unknown size
(before 2026-10-19), cannot be updated again over the network; see `recipes/ota.md` before flashing one.
- RP2350 `panic()` goes through `_exit()` and `__breakpoint()` to a HardFault, and ESPHome's rp2 crash handler
reboots within about a second (USB back 1 to 2 s after the panic). A panic during component setup therefore
boot-loops before USB CDC ever enumerates, which looks like a dead board: no port and no BOOTSEL drive. Recover
with BOOTSEL held on replug, then flash to the `RP2350` volume. To see the crash, trigger it after boot.
- A Pico 2 W can sample any of its own GPIOs from a spare PIO block (PIO2) at 25 MHz while another peripheral
drives the pin, since PIO reads the pad without taking it. That decodes WS2812-style pulses with no wires or
LEDs. Turn a light on at full brightness before probing, or color correction writes zeros. The sample FIFO
overruns now and then; count only full captures.
- A Pico 2 W also makes a byte-exact fake I2C sensor: a raw RP2350 I2C0 interrupt handler (GP4/GP5) that answers
each RD_REQ with one byte from a 256-byte register file, so any read length works (used for BME280/BMP280 in
esphome#22236). The ESP32-S3 I2C slave v2 driver is not usable for register emulation: answering from a task or
straight from the interrupt both gave shifted multi-byte reads.
## BW15 kit (RTL8720CF, LibreTiny rtl87xx)
- The kit's CH340 wires RTS to CEN and DTR to PA00 (boot strap). A plain pyserial open asserts both and
holds the chip in reset, which is why `esphome upload`, plain `ltchiptool` and `esphome logs` all fail
("Timeout while linking", or silence). `scripts/flash_rtl87xx_kit.py` sets DTR high and RTS released
on every open, pulses RTS once so the ROM answers `ping`, and after the command drops DTR and pulses
RTS to boot the app. Run it with the PlatformIO LibreTiny penv Python.
- `flash write -d <port> <uf2>` takes no family argument; `flash read -d <port> -s 0 -l <len>
realtek-ambz2 <out>` does.
- Capture with `serial_capture.py --released`. The ESPHome log is on the flashing UART already.
- The macOS CH340 driver only pushes DTR/RTS to the wire once a session has driven them, so the first
plain open after a replug streams logs and the second is silent; always open with the lines released.
- Driver quirks seen on `dev`: `WiFi.begin` can refuse the real network on the first try after bogus
credentials (it connects after two cooldowns); right after connecting while the AP is still up the
driver can bus-fault in `rtw_is_adapter_up` (`R0 = 0xdeadbeef`) and reboot; the AP restarts on every
STA retry, so stations cannot stay joined; `WiFi.begin` fails synchronously for an absent network and
lands in a cooldown at once; connecting blocks the loop 2.5 to 4.1 s.
- Decode faults with `arm-none-eabi-addr2line -e <build>/.pioenvs/<name>/raw_firmware.elf -f -C -i <PC>`
from `~/.platformio/packages/toolchain-gccarmnoneeabi/bin/` (`raw_firmware.elf`, not `firmware.elf`).
Fault dumps print PC, LR and R0 to R3.
- The AmebaZ2 SDK sets `LWIP_TCPIP_CORE_LOCKING 0`.
- The `rtw_is_adapter_up` bus fault after `Disabling AP` happens on LibreTiny 1.13.0 and 1.14.0 alike
(2 of 4 and 3 of 3 runs in #21531); run at least four rounds per build before blaming a PR for it.
- On a fault the ROM handler (ram_vector_table entries 3 to 7) prints a dump of about 4 KB in 0.4 s and
then spins; only the watchdog resets the chip (10 s after `arch_init`, 1 s once the ESPHome crash
handler re-arms it). `.ram.bss.noinit*` (`.system_restore_data`) survives that reset. The core has no
FPU. For a crash that fires once, guard an `interval` lambda with
`!libretiny::crash_handler_has_data()`. For a handler mode (MSP) fault, point vector 16+11 (SDIOD,
unused) at a trapping function and set bit 11 in NVIC ISER and ISPR (0xE000E100, 0xE000E200).
- OTA slots (esphome#22012): a serial `ltchiptool flash write` fills both OTA1 and OTA2, and the slot flag decides
which one boots (`OTA1 USE` or `OTA2 USE` in the ROM banner). Each OTA writes the other slot, so a test that needs
the OTA1 to OTA2 direction runs two OTAs in a row. On dev before #22111 a deflate OTA into OTA2 corrupted the
image, and the next restart hung at `System_Init1` until a serial reflash.
- If the chip still waits in the ROM after a serial flash, pulse CEN to GND once (TX2 floating) to boot the app.
`expected ACK` failures at random blocks mid-transfer can come from one USB hub port; another port fixed them.
- Its Wi-Fi is slow and drops (esphome#21742): a 300 KB deflate OTA takes 3 to 10 minutes, so give the uploader 30
minutes, not 10.
- Wrong-MD5 OTA test without changing firmware: monkeypatch `espota2.hashlib.md5` so only the image checksum (data
over 64 KB) returns a wrong hexdigest. Give each build its own `name:` and read `device_info().name` after a
restart to see which image booted.
## BK7238, WB3S, CB3S (BK7231N) (LibreTiny bk72xx, CH340, RTS on CEN)
- Stock ltchiptool closes and reopens the port after its reset, and pyserial raises both lines on open,
holding CEN low through the BootROM window. `scripts/flash_bk72xx.py` opens with both released and
pulses the reset right before the link checks. A write takes about 75 s. Only a CEN or power reset
reaches the downloader; no software reboot does.
- ESPHome logs on UART2 by default; `logger: hardware_uart: UART1` puts them on the flashing adapter.
- Opening the port may reset the chip (bootloader banner on open) or may not, depending on the adapter and
what pyserial does with DTR and RTS; `serial_capture.py --reset` pulses RTS on CEN and always does, and
`lt_get_reboot_reason()` reports that as Power-On. Check for the banner at the start of a capture before
assuming either.
- `flash_bk72xx.py` misses the link now and then (`Timed out attempting to link with chip`); retry up to 3
times before suspecting the board.
- Crashes: `__builtin_trap()` and a call into unmapped memory both end as an undefined-instruction trap
(`bk_misc_get_start_type()` 6, `lt_get_reboot_reason()` Crash); reads, unaligned loads and stores to
unmapped addresses never fault on the ARM968. Without Wi-Fi the SDK trap handler spins with interrupts off
for 10 s and the hardware watchdog resets the chip. With Wi-Fi connected a dev build hangs forever after a
crash, and never resets from a plain `portDISABLE_INTERRUPTS(); while (1) {}` either: the boot-time
watchdog is dead once Wi-Fi is up, for any lockup. The crash handler fix (#21012) re-arms the watchdog
from its wrapper, after which the reboot comes within a second (BK7238 and BK7231N).
- The SDK prints nothing on UART1 under `sdk_silent: all`; the bootloader then prints the banked
`cpsr/spsr/r13/r14` of SVC, IRQ, FIQ and SYS plus `ST:` (the retention register) before `go os_addr`.
A CEN or power reset wipes ITCM (reads `0xaaaaaaaa`), so only a watchdog reset keeps a record there. What
survives that reboot on the BK7238: ITCM (`0x3F0000..0x3F4000`) and the top 96 KB of SRAM
(`0x428000..0x440000`, the heap); the bootloader zeroes SRAM up to about `0x420000` and rewrites
`0x400024..0x4000FF` with its own register dump every boot, so neither a `.noinit` after `.bss` nor the
SDK's saved register banks are usable. Code is compiled Thumb, the SDK assembly is ARM; in an exception
handler only r0 to r3 are shared by all modes. BK7231N ITCM is `0x3FEE00..0x400000` (4.5 KB); a `.noinit`
placed there after `.itcm.code` works for a crash record.
- Pick the board that matches the module's flash layout. A NiceMCU XH-WB3S (BK7238) needs `board: xh-wb3s` (plain
Beken layout, RF calibration at 0x1E0000). Built as `generic-bk7238-tuya` (calibration at 0x1E3000, download
partition over 0x1E0000) the firmware boots and may even join a known network, but scans come back empty and its
AP is invisible to clients, with no warning in the log. If scans are empty, check the layout first.
- The BK7238 bootloader prints `App verify failed! Need to recovery factory firmware.` on every boot with any
build; it is harmless. Even with the right layout an ESP32 client did not see the BK7238 fallback AP on
LibreTiny 1.13.0 or 1.14.0, so the wifisave hammer cannot run on it.
- Moving a BK7231N device (CB3S) that sits on its fallback AP to another network: join the host's Wi-Fi to
`<name>-fallback`, OTA to 192.168.4.1, then rejoin the host's own network. Moving it with `/wifisave` instead can
leave it in the captive portal's BLIND_RETRY state (no scan, `Beacon Timeout` every 46 s) until it reboots, and a
log-only serial adapter cannot reset it. Rejoining may change the host's address; update a syslog target that
points at the old one.
- Callbacks run on the `async_tcp` task and log lines can lose a byte. Wi-Fi connect takes tens of ms;
radio enable 160 to 278 ms, disable about 200 ms.
- OTA install: the BK7238 bootloader installs any complete download whose own CRC passes at the next restart, even
when ESPHome refused the update; an incomplete download fails `rt_ota_part_fw_verify` (`Verify firmware CRC32
... !=`) and the old image stays.
- Power save: on the BK7238, `power_save_mode: light` with LibreTiny 1.14.0 gives ping times of 3 to 6 s because
the BDK sets a listen interval of 30 beacons when `CFG_LOW_VOLTAGE_PS` is 1 (esphome#19491).
## BW12 and other AmebaZ boards (RTL8710BX, LibreTiny rtl87xx)
- On a bare module wired to a plain USB-UART (the bench's BW12), download mode is a hand strap: CEN to
GND, TX2 to GND, release CEN, release TX2. Such an adapter does not drive CEN, so neither ltchiptool nor
`serial_capture.py --reset` can reset the chip. A development board that wires DTR and RTS to CEN and the
download pin enters download mode from the tools, like the BW15 kit; the notes below on baud rates still apply.
- ltchiptool links at 1.5 Mbaud and reads the system data at 0x9000 at that rate before it writes at
115200. A CH340 drops bytes there (`Data read error at 0x9000`, `Timed out waiting for Quiet-Handshake`)
and the run gives up without writing. `-B 115200 -b 115200` moves the link to 115200 first and works.
Start the command with `-t 120` so it is already polling while the board is strapped.
- After a failed run the ROM may sit at another baud rate and no longer link; strap again.
- The device builder frontend's AmebaZ flasher follows ltchiptool (link and system read at 1.5 Mbaud),
so it can hit the same read failure on the same adapters.
- Power the module from the adapter's 5 V pin into its own regulator; the adapter's 3.3 V pin cannot
carry the Wi-Fi transmit peaks.
- Capture with `serial_capture.py --released`. With DTR and RTS asserted on the open port, a software
reboot (`App.safe_reboot()`, the restart button) lands in the ROM downloader (`UARTIMG_Download 2`)
and stays there until CEN is pulsed. After a flash the chip also waits in the ROM until CEN is pulsed.
- A full flash takes 50 to 220 s at 115200. While the board is on Wi-Fi, OTA (port 8892) saves the strap,
but the board's Wi-Fi latency (one to two seconds a ping) can make the upload time out.
- `sdk_silent: none` under `framework:` keeps the Wi-Fi driver's join log (`start auth to`, `auth success,
start assoc`, `association success`, `sta recv deauth reason code(N)`); LibreTiny mutes it during the
connect otherwise. `wifi_get_last_error()` after a failed `WiFi.begin()` gives the SDK's reason
(1 no network, 2 connect failed, 3 handshake failed, 6 auth failed); LibreTiny only logs `ret=-1`.
- Some modules ship with no RF calibration in efuse, only the chip ID and MAC. Dump the logical map with
the ROM's `EFUSE_LogicalMap_Read(buf)` (512 bytes): TX power indexes are at 0x10 to 0x1A, crystal trim
at 0xC9, MAC at 0x11A; 0xFF means the driver uses its default (trim 0x20). Linking with
`-Wl,-wrap,EFUSE_LogicalMap_Read_ACUT` lets a wrapper rewrite blank bytes before the driver parses
the map on each radio start. See `recipes/libretiny.md` for the per-boot trial harness used to A/B them.
- Scan results report WPA2-AES access points as `WPA PSK`: LibreTiny truncates `rtw_security_t` to
`uint8_t` before mapping it. Cosmetic. Open networks come out as `WIFI_AUTH_INVALID` (255) on both
AmebaZ and AmebaZ2, so `auth != WIFI_AUTH_OPEN` marks them encrypted.
- After a BSSID plus channel join, LibreTiny's `set_pscan_channel(ch, false)` leaves the driver with no
channel to scan, so the next SSID only join fails at once (no `start auth`), and the first scan after a BSSID
join comes back empty (no results in about 62 ms on the BW15). A `wifi_set_pscan_chan` list of channels 1 to 13
returns 0 but leaves only the last channel enabled, and re-applying the channel plan does not help either
(AmebaZ2 reports plan 0xFF; AmebaZ's `rtw_set_chplan_cmd` rejects plans above 0x58 except 0x7F). What works
(esphome#21749, BW15): set the one-channel pscan list yourself and pass channel 0, so the join's own scan
rebuilds the full list; setting a placeholder SSID `-` before narrowing (esphome#21754) kept joins as fast as
dev with the first scan full on every boot. Not yet confirmed on AmebaZ.
- A 4-way handshake that never finishes after association is reported as `RTW_WRONG_PASSWORD` on AmebaZ
even with the right password; AmebaZ2 reports a real wrong password as a 4-way handshake timeout.
- The driver also posts a SCAN_DONE (number 0) inside every join, on AmebaZ2 too.
## BW16 kit (RTL8720DN, AmebaD)
- The kit's own USB-C (CH340) is on LOG_UART and flashes fine. Its two-transistor circuit resets while
RTS alone is asserted and straps BURN while DTR alone is; both asserted does nothing. ROM entry is
esptool's classic sequence (`dtr:false,rts:true` 100 ms, `dtr:true,rts:false` 400 ms, both false); the
first pulse after a replug can be lost, retry up to three times.
- Any reopen resets the chip, 460800 is flaky, 115200 is solid: one open per session, in-place baud
changes only. The ROM and the loader NAK continuously while idle, so ACK scans must drain first.
- The AmebaD core has no mDNS responder (`mdns: disabled: true`).
## LN882H
- ltchiptool forces 1 Mbaud for writes; adapters that cannot hold it fail with "Timeout while linking"
or die mid-write. Patch `LN882H_YM_BAUDRATE` in the penv's `ltchiptool/soc/ln882h/util/ln882htool.py`
to 115200 (lost on reprovision). Weak 3.3 V from the adapter: feed the module's 5 V pad instead. Short
BOOT to GND while the tool connects. OTA afterwards.
- `USE_WIFI_AP_EXCLUSIVE` (one radio mode at a time) exists only on LN882x; compile-check changes there.
- The ESPHome OTA port on LN882x is 8820, not LibreTiny's 8892 (BK72xx, RTL87xx); helper scripts that hardcode
8892 get `Connection refused`.
- WL2H-U modules with the Tuya flash layout: app at 0x007000 (0x113000 long), OTA at 0x11A000 (0xA8000 long). A
full OTA upload over a slow link takes 2 to 14 minutes.
- UF2 block order differs per family: LN882H puts the device image first and the flasher image after it, BK72xx
puts the flasher image first and the device image last. The LN882H bootloader installs a complete, valid OTA
partition even when the upgrade state is still `UPG_STATE_DOWNLOAD_ING` (esphome#22111).
- Without serial access to recover, never send a corrupted image; wrong-MD5 and cut-upload tests with valid
images are safe.
## nRF52840
- Nordic PCA10059 dongle: the factory Open DFU bootloader enumerates as `1915:521F` on its own port
name; the app as `2FE3:0100` with two CDC ports, ESPHome log on the second. Only Nordic
`nrfutil nrf5sdk-tools` works (`pkg generate --hw-version 52 --sd-req 0x00 --application-version 1
--application zephyr.hex app.zip`, then `dfu usb-serial -pkg app.zip -p <port>`); ESPHome downloads
it on the first build. GPREGRET does not enter the bootloader; a pin reset through P0.19 does, which
`dfu: true` wires up on this board. A pulsing red LED means bootloader; the side RESET button
re-enters it.
- Makerdiary MDK USB dongle: UF2 bootloader without SoftDevice, app at 0x1000, `UF2BOOT` volume,
adafruit-nrfutil, GPREGRET 0x57 works. The running app enumerates as `1915:CAFE` or `239A:0029`. RGB LED
active low (red P0.23, green P0.22, blue P0.24), button P0.18.
- Both boards reflash without a button once they run a `dfu: true` build: `esphome upload --device <any app CDC
port>` on the PCA10059, a 1200 bps open of the log port plus a copy of `zephyr.uf2` to the volume on the ItsyBitsy.
- Adafruit ItsyBitsy nRF52840 Express (UF2 bootloader 0.9.0 with S140 6.1.1, bootloader port `239a:0051` plus an
`ITSY840BOOT` volume): the board DTS already has `cdc_acm_uart0`, so the logger port is the first CDC
port and a `usb_cdc_acm` interface 1 the second. A `dfu: true` build enters the bootloader on the
1200 bps touch (an app without it needs a double tap on RESET); `adafruit-nrfutil` over the bootloader
serial port can fail, copying `.pioenvs/<name>/zephyr/zephyr.uf2` to the volume works (the copy reports
an I/O error as the board reboots, which is normal). Reboot a running `dfu: true` app with a 2001 bps touch.
- The PCA10059 board DTS already defines a `cdc_acm_uart` node, so every ESPHome CDC port is one USB port
later than its number (log on `cdc_acm_uart0` is the second port). A third CDC instance needs
`CONFIG_USB_MAX_NUM_TRANSFERS` above 4 or it never moves data (see `recipes/usb_cdc_acm.md`).
- USB CDC boot output: the Zephyr legacy stack's `cdc_acm` TX ring is 1 KB and `uart_poll_out` drops when it
is full, so anything printed in one burst beyond about 1 KB (a coredump, a long table) is lost even with
the port open, and the logger warns `logger took a long time`. Print one line per `loop()` instead.
- Zephyr settings survive a reflash: key a `restore_value` global by a `run` substitution when a test needs
a never-saved value.
- Thread: nRF52 `openthread:` accepts only `tlv:`; the individual keys (network_key, channel, ...) are rejected at
validation. To list nearby networks with channel and PAN ID, call
`otThreadDiscover(InstanceLock::acquire().get_instance(), 0, 0xFFFF, false, false, cb, nullptr)` from an
`interval:` lambda in an included header; results arrive on the OpenThread thread and log fine.
- A wrong network key on a real network's channel and PAN ID makes the device form its own partition as leader on
that PAN within about 30 s; take it off Thread at once. Never try guessed datasets against a network in use.
## Waveshare ESP32-S3-ETH with the OV5640 camera module
- Native USB console (`303a:1001`), ESP32-S3R8, 16 MB flash, 8 MB octal PSRAM, W5500 on SPI (MOSI 11,
MISO 12, SCLK 13, CS 14, INT 10, RST 9), TF card on 4..7, WS2812 on 21.
- Camera header (vendor schematic): XCLK 3, SIOD 48, SIOC 47, VSYNC 1 (a 0 ohm link to GPIO1, alternative
GPIO16), HREF 2, PCLK 39, D0..D7 = 41, 45, 46, 42, 40, 38, 15, 18. PWDN is tied to GND and RESET is an RC to
3.3 V on the board, so no reset or power-down GPIO exists.
- It can run from PoE and USB-C at once, so the USB-C can move from the host to a USB device for `usb_uart` or USB
host tests while the board stays up; flash and read logs over Ethernet while it is unplugged. In USB host mode
the USB-C is the host port after the first flash: log over the API with `logger: hardware_uart: UART0`.
- A crash-looping image can wedge its USB console until a BOOT replug. Never force allocation failures on it by
hogging RAM: Wi-Fi then aborts in `operator new` or the loop task trips the task watchdog.
- GPIO8 switches the camera 3.3 V rail through a P-channel MOSFET: LOW = camera powered, gate pulled up so
the camera is off by default. `power_down_pin: GPIO8` only pulls it low 10 ms before the probe, which is
not enough; use `switch: gpio GPIO8 restore_mode: ALWAYS_OFF setup_priority: 800` plus `on_boot:
priority: 700` with `delay(1200)` and `esp32_camera: setup_priority: 200`
(`templates/rtsp-waveshare-s3-eth-dut.yaml`). `esphome config` rejects a config that uses GPIO8 for both the switch
and `power_down_pin` (pin reuse), so it is one or the other.
- The sensor at SCCB 0x3C answers only with XCLK running, so the ESPHome i2c scan at boot (before XCLK)
reporting no devices on 48/47 is expected. If the SCCB ID register (0x3100 = 0x78) reads fine but every
0x30xx register reads 0x00 (`Detected camera not supported`, 0x106), reseat the ribbon before blaming
software; `templates/waveshare-s3-eth-camdiag.yaml` runs that probe with LEDC XCLK and raw SCCB reads.
## ESP Thread Border Router board v1.2 (S3 host + H2 RCP)
- S3 host on USB JTAG serial, H2 RCP on its own USB. Spinel UART1 from the host: `rx_pin: GPIO17`,
`tx_pin: GPIO18`, RCP reset `GPIO7` active low, 460800. The config needs `network: enable_ipv6: true`.
- The shipped H2 firmware fails `CheckRadioCapabilities` with IDF 5.5; build `examples/openthread/ot_rcp`
for esp32h2 with ESPHome's own IDF (`IDF_PATH` at the cached framework, its penv and tools,
`IDF_PYTHON_CHECK_CONSTRAINTS=no`) and flash with esptool at 0x0, 0x8000 and 0x10000.
- A crash-looping S3 pulses the H2 reset every boot, so the H2 cannot be flashed and the S3 will not
enter its bootloader over USB. Hold S3 BOOT, tap S3 RST, flash the H2, release, then replug both.
- `dns-sd -L <name> _meshcop._udp local.` shows the `omr` prefix; it disappears when routing is dead.
Keep one capture per chip; never reset the H2 over USB mid-test unless that is the test (the host
logs `Unexpected RCP reset: RESET_OTHER` and recovers).
## Building against a patched LibreTiny
- Clone LibreTiny at the tag ESPHome pins, commit the patch, and set `framework: version: <tag version>` plus
`source: file://<clone>` under `bk72xx:` or `rtl87xx:`. PlatformIO installs it as
`~/.platformio/platforms/libretiny` (the stock copy is `libretiny@src-<hash>` and is not touched).
- A later commit in the clone is not picked up by the next build; patch the installed copy or remove it. Remove
`~/.platformio/platforms/libretiny` when done.
- BDK headers such as `power_save_pub.h` have no `extern "C"`; wrap them when including them from the Arduino
core's C++ files.
## LibreTiny crash and abort() facts (esphome#21596, #22288)
- `abort()` on dev: the BK7238 hangs for good (the main loop stops and the watchdog never fires once Wi-Fi is up;
recover with an RTS pulse on CEN, `serial_capture.py --reset`). The BW15 (RTL8720CF) restarts with no crash
record. The LN882H reboots only after about 18 s through the watchdog (`WDT Reset`), with no record: the SDK's
`abort()` and `_exit()` (`components/libc/newlib_stub.c`) and its FreeRTOS `configASSERT` are spin loops. With
#22288 all three reboot in 1 to 2 s and log `Reason: Abort`, with the PC at the call site and no `LR:` line.
- `assert()`, `std::terminate` and a failed `new` all reach `abort()` (nano libsupc++). `raise(SIGABRT)` returns,
because `_kill` is a nosys stub.
- `__builtin_trap()` faults on every board. A store to `nullptr` or 0xDEADBEE0 does not fault on the BK7238. On
the BW15 a `nullptr` store does not fault, and loads and stores at 0xDEADBEE0 give only imprecise bus faults
(CFSR 0x400, no BFARVALID), so testing the fault address path needs another Cortex-M chip.
- BK7238 safe mode: each quick crash reboot counts toward it (`Last reset too quick; invoke in N restarts`), so
back-to-back crash tests can drop the board into safe mode.
- LN882H: the previous crash is replayed to every new API log client until the next crash; that is expected, not a
double record. Once, the first `__builtin_trap()` after a fresh OTA took about 12 s to reboot; retries took 2 to
3 s and it did not reproduce.
- `~/.platformio/packages/toolchain-gccarmnoneeabi` can vanish between a build and the decode (it comes back with
the next LibreTiny build). Until then the `arm-none-eabi-addr2line` and objdump of
`toolchain-rp2040-earlephilhower` read any ARM ELF.
- RTL8720C: a noreturn `bl abort` can be the last instruction of a function, so the raw return address points at
padding addr2line cannot place. Decode `(addr & ~1) - 2` to get the call line; #22288 records it that way.
- Abort reports (#21596): early heads put LR 0x00000000 first in the address list; later heads drop a zero LR, so
an abort report starts with the backtrace.
## Waveshare ESP32-C6-GEEK
- Native USB JTAG serial (`303a:1001`), 16 MB flash, 1.14" ST7789 LCD and TF card; the vendor docs give no GPIO
numbers. Pins that read a fixed level against the internal pulls: 1, 2, 7, 20, 23 high, 6 low. Free for pad
tests: 0, 3, 4, 5, 18, 19, 21, 22 (see `recipes/gpio_hold.md`).
## Waveshare ESP32-P4-Module-DEV-KIT (USB host)
- ESP32-P4 rev v1.3, 16 MB flash, console on a CH343 (`1a86:55d3`). Other boards use the same chip for their
console, so check with `esptool chip_id`.
- USB host for `usb_host`: set the Host/Device jumper to HOST and use the bottom USB-A port nearest the Ethernet
jack (the high-speed OTG controller); the other USB-A ports and the USB-C marked "USB" do not reach it. The ports
are unlabelled. The port powers the device.
- ESP-IDF programs the FIFO split only when a device connects: read `GRXFSIZ`, `GNPTXFSIZ` and `HPTXFSIZ` at
`DR_REG_USB2_BASE` + 0x24, 0x28 and 0x100 after enumeration. GHWCFG3 (0x4C, high 16 bits) reads 896 lines. The
default split is RX 512, NPTX 256, PTX 128.
- Not every P4 board has a USB host port; check before planning a `usb_host` test on one.
## Gelidus Research PS1 v2.3 (LD2420 presence sensor)
- ESP32-D0WD-V3 rev 3.1 on a CH340 (`1a86:7523`); `esphome upload --device <port>` works directly.
- LD2420 UART: TX GPIO17, RX GPIO16, 115200 (radar firmware v1.6.1). Status LED GPIO23, night light PWM on GPIO25.
- The vendor package is at github.com/GelidusResearch/grps (`packages/grps-ld2420.yaml`); copy it locally for tests.
- The radar needs a person in its field. Energy frames are `F4 F3 F2 F1 23 00 <presence> <range cm LE16> ...`; a
UART `debug:` block on RX shows them.
## ESP32-C3 Super Mini (native USB, 4 MB XMC flash)
- Shows up as `303a:1001`; confirm with `esptool --port <port> chip_id`. Board `esp32-c3-devkitm-1`,
`logger: hardware_uart: USB_SERIAL_JTAG`. Avoid GPIO2, 8 and 9 (strapping; 8 is the LED, 9 is BOOT).
- A 6-pin BME680 breakout (CS, ADDR/MISO, SCL, SDA, GND, VCC) on SDA GPIO6 and SCL GPIO7 with CS and ADDR left
open answers at 0x77 through the breakout's pull-ups, and the `bme680` platform reads fine.
- BME688 parallel mode never reads in `bme68x_bsec2` on dev: the read timer is re-armed by each 30 ms run before
its 41.6 ms delay ends. Entering parallel mode at all needs gas estimates subscribed at `BSEC_SAMPLE_RATE_SCAN`
and no IAQ outputs.
## mDNS responder tests (#22267)
- When the host's multicast does not reach the device, query its port 5353 directly as legacy unicast (a
python-zeroconf packet sent from a normal UDP socket) to dump records or hammer the responder.
- On a crowded Wi-Fi channel, back-to-back query loss swung from 0 to 14% between builds for no code reason. Judge
responder timing on an Ethernet board.
## nRF54LM20 DK (PCA10184, on-board J-Link)
- The power switch must be ON or nothing enumerates. The ESPHome log (uart20) is on the second J-Link VCOM port;
the first is unused.
- Flash with `esphome upload <yaml> --device JLINK` (sdk-nrf toolchain); the LM20 needs no west `--device` override.
The J-Link re-enumerates after the flash, so start the capture after the port comes back.
- Reset without halting: JLinkExe `-device NRF54LM20A_M33 -if SWD -autoconnect 1` with `w4 0xE000ED0C 0x05FA0004`
(plain `r` and `g` halt and resume, no reboot).
- LED0 P1.22, LED1 P1.25; BUTTON0 P1.26, BUTTON1 P1.09, BUTTON2 P1.08, BUTTON3 P0.05 (active low, pull-up). GPIO
P1 registers at 0x500D8200 (IN +0x00C, PIN_CNF +0x080), P0 at 0x5010A200.
- Binary sensor state changes are not logged at DEBUG; log the states or count `on_press` to see button presses.
@@ -1,72 +0,0 @@
# Proven test flows
Each flow names the pull requests it was used on, so their result tables show what to post.
One file per component, named after it:
- [`api.md`](api.md): noise handshake and OTA encryption on the ESP8266, outgoing connection wake timing on deep sleep and after a Wi-Fi drop, user defined action listing and execution with a raw plaintext client, store_yaml recovery over Noise or plaintext
- [`ble_midi.md`](ble_midi.md): BLE MIDI client against a fake ESP32 instrument, every packet shape and the send actions
- [`captive_portal.md`](captive_portal.md): fallback AP and /wifisave hammer
- [`cse7766.md`](cse7766.md): Sonoff S31 parser check over the API
- [`espnow.md`](espnow.md): ESP8266 broadcast receive
- [`hdmi_cec.md`](hdmi_cec.md): two-board wire
- [`http_request.md`](http_request.md): update manifest URL changed at run time, every setter shape, a swap under a running check, non-blocking request actions with loop gap, queue, cancel and reboot checks, OTA request cases with basic auth and MD5 sources
- [`ld2420.md`](ld2420.md): hub setup and sensor states with a simulated module on a UART0 loopback (energy and simple mode)
- [`ld2450.md`](ld2450.md): polygon zones, zone number round trip through the radar's readback, ESP8266 loopback harness without a radar, presence hold and link loss on a frame stream, BT MAC readback
- [`ld2412.md`](ld2412.md): output pin level through the basic configuration command, held back writes
- [`libretiny.md`](libretiny.md): rtc preference emulation, BK72xx and RTL8720C crash report on the next boot with a ROM dump matcher, BK7238 BLE bond store safety with a full flash backup and per partition diff, BK7238 OTA versus the board layout and bootloader
- [`modem.md`](modem.md): PPPoS modem component boot check with no modem attached, loop blocking and disable timing
- [`mqtt.md`](mqtt.md): broker bench, QoS, reconnect, crash log over MQTT, WebSocket transports with a local and a public broker, TLS trust sources (own CA, client certificate, certificate bundle, no verification) with the CLI check, MAC suffix topics and will messages on two boards, shutdown message delivery on restart, disable and deep sleep
- [`nrf52.md`](nrf52.md): dongle board support, zephyr_ble_server connection slot under reordered callbacks, SMP over UDP OTA over Thread with reset faults, MCUboot swap limit and stuck slot recovery, TCP stack probe
- [`online_image.md`](online_image.md): stalled and malformed downloads, PNG, JPEG, BMP and QOI decode time per loop pass with large images and small buffers
- [`openthread.md`](openthread.md): border router on the S3 host plus H2 RCP
- [`ota.md`](ota.md): upload without a configuration and the refusal checks, overlap and lock, timeouts, deflate, upload timing A/B per build and board with deflate and raw, on-device inflate benchmark, OTA automations on two platforms
- [`rtsp_server.md`](rtsp_server.md): camera streaming on the Waveshare ESP32-S3-ETH
- [`scheduler.md`](scheduler.md): loop wake A/B, interval startup delay and control from lambdas
- [`udp.md`](udp.md): datagrams, multicast, sockets, `udp.write` payload shapes
- [`usb_cdc_acm.md`](usb_cdc_acm.md): nRF52840 dongle host driver
- [`wifi.md`](wifi.md): reboot_timeout with a fallback AP, DHCP lease cache, Easy Connect (DPP), WISP bridge with an ethernet upstream, reboots against a WPA2/WPA3 PMF access point, WISP and ALWAYS_ON AP switching, AP restarts with WPA3 mixed and LIGHT power save
- [`zephyr.md`](zephyr.md): preferences on the nRF52840 dongle
- [`zephyr_coredump.md`](zephyr_coredump.md): crash and decode on nRF52 boards
- [`zwave_proxy.md`](zwave_proxy.md): frame checksums on a live proxy
- [`globals.md`](globals.md): restoring globals with storage rtc and flash across every reset kind
- [`homeassistant.md`](homeassistant.md): light platform mirrored from a local Home Assistant, held reports versus later calls
- [`usb_audio.md`](usb_audio.md): USB audio speaker and microphone, the usb_host FIFO split, and Music Assistant playback through sendspin
- [`dfrobot_sen0395.md`](dfrobot_sen0395.md): SEN0395 mmWave command flow, module quirks and overlong lines through its error reply
- [`speaker.md`](speaker.md): media player pipeline tasks on the Connect AUX-2 with the `speaker` platform player
- [`web_server.md`](web_server.md): state SSE stress and the HTTPD task stack on web_server_idf, entity icon and device class readback
- [`uart_sim.md`](uart_sim.md): UART sensors simulated on a classic ESP32 with loopback and cross-wired UARTs
- [`gpio_expander.md`](gpio_expander.md): interrupt driven expander inputs, loop idle checks, testing a device out of reach
- [`led_strip.md`](led_strip.md): forcing a failed strip allocation, RMT symbols per chip, loop cost per strip
- [`remote_base.md`](remote_base.md): remote_receiver protocol decoding through a one-pin loopback on ESP32 and ESP8266, no IR hardware
- [`xiaomi_ble.md`](xiaomi_ble.md): Xiaomi, ATC and PVVX parsing by injecting scan results into the ESP32 tracker or advertising them from a second ESP32, real AES-CCM frames, duplicate filter model
- [`ble_terminate.md`](ble_terminate.md): proxy disconnect against a peer with peripheral latency
- [`i2c_slave.md`](i2c_slave.md): fake I2C slave on a D1 mini, ESP32 hardware master as the control
- [`fake_i2c.md`](fake_i2c.md): fake I2C devices with no chip: in-firmware buses for many drivers, a Pico 2 W BME280/BMP280 target, a DS2482-800 simulator, NACK injection for vl53l0x
- [`gpio_hold.md`](gpio_hold.md): GPIO hold through the ISR pin API, pad read back with no wiring, per chip pin notes
- [`ble_event_inject.md`](ble_event_inject.md): made up GAP and GATTC events fed into the ESP32 BLE handlers from a button
- [`light_sleep_gpio_wake.md`](light_sleep_gpio_wake.md): GPIO wakeup from auto light sleep with an LEDC wave that keeps running in sleep, and with an external wave and peripheral power-down on the ESP32-P4
- [`manual_ip_and_web_handlers.md`](manual_ip_and_web_handlers.md): station, AP and Ethernet manual IP, web handlers added late and web OTA with web_server, captive_portal or prometheus
- [`ble_server_security.md`](ble_server_security.md): esp32_ble_server pairing, encrypted and MITM characteristics, subscription before and after pairing, bond reuse per ESP-IDF version
- [`prometheus.md`](prometheus.md): date, time and datetime metrics in UTC and another time zone
- [`ble_adv_triggers.md`](ble_adv_triggers.md): BLE service and manufacturer data advertise triggers over the air on the ESP32 and BK72xx trackers, with a second ESP32 advertising known frames
- [`sun.md`](sun.md): on_sunrise and on_sunset by sweeping the observer's longitude, one full sweep in about 17 minutes
- [`sensor_filters.md`](sensor_filters.md): every sensor, binary_sensor and text_sensor filter shape fed a fixed input sequence, outputs compared bit for bit between builds
- [`led_driver_sniff.md`](led_driver_sniff.md): bit-banged LED drivers captured on the ESP32's own pads with SPI slaves through the GPIO matrix, no chips
- [`hub_input_sim.md`](hub_input_sim.md): matrix_keypad, wiegand, rdm6300 and key_collector driven from a D1 mini's own pins and UART loopback
- [`value_range.md`](value_range.md): sensor and number on_value_range with a fixed sequence and a restart
- [`ezo_fake_bus.md`](ezo_fake_bus.md): the ezo component against a fake I2C bus that answers like an EZO circuit
- [`twai_self.md`](twai_self.md): esp32_can on_frame with the controller hearing its own transmit pad, no transceiver
- [`buttons.md`](buttons.md): output button pad timing, homeassistant button through a raw API client with the wizard input, uart button on the UART0 loopback
- [`rs485_frame.md`](rs485_frame.md): DLE/STX/ETX bus on an ESP32-C3 with a cross-wired simulated bus device (frame cases, gate timing)
- [`hx711.md`](hx711.md): fake HX711 driven from the other core, every published value matched to the served conversion
- [`automation_trace.md`](automation_trace.md): automation codegen A/B, a marker trace of chains, conditions, loops and script modes over the API
- [`bluetooth_proxy.md`](bluetooth_proxy.md): held GATT link after a half-open API session, frozen Home Assistant stand-in
- [`crash_report.md`](crash_report.md): crash buttons, fetching the previous boot's crash report over the API, per-chip abort facts
- [`https_idf.md`](https_idf.md): web_server_idf HTTPS test component, listener switch, stalled TLS clients, bad key
- [`mdns.md`](mdns.md): legacy unicast mDNS dump, hammer and latency straight to the device
- [`sim_buses.md`](sim_buses.md): PCF8574/HD44780, MAX7219, SPI spy, packet_interface and SN74HC165 simulators, status LED probe, fake Home Assistant, cg.static_buffer probes
- [`sigma_delta.md`](sigma_delta.md): pulse density of the sigma_delta speaker pin read inside the ESP32-P4, rtttl note onset and release
- [`microphone_http_stream.md`](microphone_http_stream.md): raw PCM over HTTP with a counter fake mic or a USB mic, multi-reader client
- [`i2s_audio.md`](i2s_audio.md): I2S microphone fed by an I2S TX channel on the same S3 through three jumpers
- [`voice_assistant.md`](voice_assistant.md): late TTS start on the Voice PE with a slow announcement URL
@@ -1,58 +0,0 @@
# api
## Noise handshake and OTA encryption on the ESP8266 (#19062, #19233)
Host side timing is useless on a weak link; use an on-device bench with the minimum of five runs over
two boots. Provision a key with `noise_encryption_set_key` through aioesphomeapi and upload with
`espota2.run_ota(host, 8266, None, bin, noise_psk=key)` when the key is not in the yaml.
## Outgoing connection wake timing on a deep sleep build (#21077)
`templates/deep-sleep-outgoing-dut.yaml`: classic ESP32 ESP-IDF, `wifi: fast_connect`, `api: encryption` with a bare
`outgoing_connection:`, `deep_sleep` 15 s run and 15 s sleep, a `homeassistant` text sensor, and `millis()` logged
from `wifi: on_connect`, `api: on_client_connected` and the sensor's first `on_value`. Home Assistant's dial-in
listener is on 6054; reuse a device name it already has. Flash by USB, `serial_capture.py PORT 360 OUT --reset` for
12 cycles, then `scripts/api_outgoing/cycles.py OUT LABEL` prints per cycle the wifi, client and state millis with
the client-wifi and state-client gaps. Wi-Fi takes 4 to 8 s after a wake, so compare the client-wifi gap, and run
the PR twice around one base run because the spread is a few hundred ms.
Results: https://github.com/esphome/esphome/pull/21077#issuecomment-6254098014
## Outgoing connection on a mains build after a Wi-Fi drop (#21085)
`templates/outgoing-wifi-drop-dut.yaml`: classic ESP32, `outgoing_connection: delay: 2s`, a "Wifi cycle" button doing
`wifi.disable`, 4 s, `wifi.enable`, a `debug` loop-time sensor, millis from the wifi and api triggers. Flash by USB,
`serial_capture.py PORT SECONDS OUT --ms`, press the button N times 40 s apart with `api_button.py DEV_IP KEY press
"Wifi cycle"`, then `wificycles.py CAPTURE LABEL` prints per drop the Wi-Fi-to-dial gap, dials and dials closed, who
connected first, and the loop-time maxima. For the loop cost of polling, repeat with an unreachable
`host: 192.0.2.1`. Home Assistant refuses a dial-in while its own session is READY (`Refusing dial-in adoption`),
so after a drop every dial is closed and HA's incoming reconnect wins 11 to 33 s later; the measurable effect is the
first dial landing in the loop the network flag flips.
Results: https://github.com/esphome/esphome/pull/21085#issuecomment-6254742791
## User defined action listing and execution without a client library (#18882)
`scripts/api/rawactions.py HOST list` speaks the plaintext native API over a raw socket and decodes every
`ListEntitiesServicesResponse` by field number (argument fields 1 name, 2 type, 3 description, 4 example, 5 optional,
6 default_value), so new wire fields show up without waiting for the client library. `rawactions.py HOST exec ACTION
k=v ...` sends `ExecuteServiceRequest` with `sint32` ints (field 5, not the legacy int32 field 2), fixed32 floats,
length delimited strings and `int[]` as repeated sint32 (field 7); `ALLOW_MISSING=1` leaves arguments out on purpose
(the device then drops the call). `templates/api-actions-dut.yaml` (D1 mini, three actions, optional variables with
defaults) and `templates/api-actions-strings-dut.yaml` (required strings) log what arrived. String arguments are
`StringRef`s that are not null terminated: copy them with `snprintf("%.*s", size, c_str())` into a buffer before
logging, and do not pass `%.*s` to `logger.log`, whose validator counts it as one pattern.
## store_yaml recovery over the native API (#16445)
`scripts/api/syrecover.py HOST KEY OUTDIR [ORIGDIR]` (KEY `-` for plaintext) builds the client library's
`APINoiseFrameHelper` around a stub `APIConnection` subclass (the compiled helper type checks the connection, and
`ConnectionParams` needs every field), sends Hello, Authentication (never answered without a password) and
`DeviceCapabilitiesRequest`, then `GetYamlRequest` (161), collects `GetYamlResponse` (162) frames by field number
(1 data, 2 done, 3 total_size, 4 encoding) until done, requests again, decompresses with `compression.zstd` (Python 3.14, or the `zstandard` package) and
unpacks the envelope with the tree's `unpack_envelope` (run with `PYTHONPATH` on that tree). Configs in
`templates/store_yaml/`: entry files in `boards/`, a package one directory above them with `!secret` and an inline
OTA password,
so the redaction and the `..` paths are exercised. Repetitive YAML compresses into one chunk even at 22 KB; a 6 KB
include of random base64 lines with `include_secrets: true` gives four chunks (1390 byte packets). Rough edge at
0bd3738430: `include_secrets: true` fails the build when a package in another directory uses `!secret` and has no
`secrets.yaml` beside it; a copy next to the package works around it.
Results: https://github.com/esphome/esphome/pull/16445#issuecomment-6335435397
@@ -1,24 +0,0 @@
# Automation code generation A/B (#21978 to #21980)
A change to how actions, conditions or scripts are generated must not change what runs or in which order.
`scripts/automation_trace/automation-trace-common.yaml` (a package) logs a marker `M <case> <values>` at every step.
It covers:
- merged action chains, delays inside chains, nested `if`/`else` with and/or/not/xor, `choose` with `else`;
- `while` with and without a delay, nested and dynamic `repeat`, `wait_until` and `for:`;
- `single`, `restart`, `queued` and `parallel` scripts with parameters, a self `script.stop` mid-chain;
- `on_value_range`, alarm panel triggers, and parallel scripts with `max_runs` 2, 3 and 4 that execute themselves
from an `if` branch.
`run.sh LABEL` writes the per-run file (board, Wi-Fi from `secrets.yaml`, the package), builds and flashes over
`PORT`, takes the device address from the serial log and runs `drive.py HOST OUT`. The driver records the boot run,
a "Run All" press and API-driven triggers (Chain Button twice, Num 70 and 20, Sw on and off, Sel c and a). The
runner keeps the part from `DRIVER press Run All` on in `out-at<LABEL>.trace`; diff dev against each PR head. The
boot run is partly missed while the API connects, so it is left out of the diff.
- Pass: the Run All pass reaches `M done`, no `SHOULD_NOT_RUN` or `NOT_REACHED` marker appears, and the trace is the
same on both builds.
- The interleaving of the `queued` and `parallel` scripts with later steps is timing dependent, but it was identical
across builds and runs.
- To check a real device config as well, OTA the PR build and toggle one light and one switch from an API client,
returning each to its original state, and compare states and logs with the base build. Get the owner's approval
before flashing a device that is in use.
@@ -1,28 +0,0 @@
# BLE service and manufacturer data advertise triggers (#21822, #21823, #21827)
`scripts/ble_adv_triggers` checks `on_ble_service_data_advertise` and `on_ble_manufacturer_data_advertise` over the
air on the ESP32 and BK72xx trackers.
- Advertiser: `advtrig.yaml` on any second ESP32 with BLE. Every 250 ms it switches to the next of six raw
non-connectable advertisements (`adv_frames.hpp`, random static addresses `C4:C1:38:00:00:21` to `26`):
| Address | Contents |
|---|---|
| `...:21` | service data 181C `AA01` and manufacturer data 02E5 `BB01` |
| `...:22` | service data 32-bit 12345678 `AA02` |
| `...:23` | service data 128-bit 12345678-9ABC-DEF0-1122-334455667788 (wire order) `AA03` |
| `...:24` | manufacturer data 181C `BB04` (the service UUID of `...:21`, other data kind) |
| `...:25` | two service data 181C entries, `AA05` then `AA06` (only the first may fire) |
| `...:26` | the 128-bit UUID in printed byte order, `AA07` (must not match) |
- Receivers: `rx-esp32.yaml` (classic ESP32, passive scan) and `rx-bk72xx.yaml` include the same eleven triggers
(`triggers.yaml`). `rx.hpp` counts each trigger's hits by payload (`AAnn`, `BBnn`, anything else as `other`) and
logs the table every 20 s, plus all adverts and those from the advertiser.
- `run.sh esp32|bk72xx LABEL` builds, flashes, captures 150 s and runs `check.py`, which prints PASS or FAIL. Run it
once per build (dev merge base and each PR head). About 550 hits per trigger on ESP32 and 170 on a BK7238 in that
time.
- `mac_address: 00:00:00:00:00:00` meant no filter on the ESP32 tracker before #21823 and filters on that address
after it (BK72xx always filtered). Pass `ZERO_MAC=any` for an ESP32 build from before #21823.
- BK7238: with no `wifi:` in the config the tracker logs `Scan started` but receives nothing at all, on dev too. The
BK config therefore joins Wi-Fi.
- Results: https://github.com/esphome/esphome/pull/21827#issuecomment-6489703755
@@ -1,30 +0,0 @@
# Injecting BLE GAP and GATTC events (#21698)
Some BLE paths (repeated connection parameter update failures, a disconnect in the middle of them) are hard to get
from a real peer on demand. `scripts/ble_event_inject` feeds made up events straight into the ESP32 BLE handlers.
- `ESP32BLE::gap_event_handler` and `gattc_event_handler` are protected statics and the class is `final`.
`cp_inject.hpp` reaches them through explicit template instantiation, where access checks do not apply. Its
`cpinject::run()` sends six labelled steps (`STEP1` to `STEP6`): four peers failing five times each, a success
followed by more failures, and disconnects between failures.
- `cp-inject.yaml` is a package for a copy of a proxy config: it adds the include, a VERBOSE logger with the busy
tags back at DEBUG, and an `Inject conn param events` button. Press it with `scripts/api_button.py` while a
log capture (`esphome logs ... --device <ip>` under `timeout`) runs, then count the warning and verbose lines per
step on the PR and on dev.
- The handlers push into a queue and event pool that take a single writer, normally the Bluetooth task. Injecting
from the main task while real events arrive can corrupt them, so the button stops the scan, waits for it to end,
injects and starts it again. Run it with no active proxy connections (no Home Assistant BLE client holding one).
- Fake disconnects use `gattc_if` 0xFE: every client and proxy connection filters on its own `gattc_if_`, so the
queued event reaches only the shared handler. Do not use 0xFF (`ESP_GATT_IF_NONE`), which every client accepts.
- The fake peers (`C0:FF:EE:00:00:0n`) are never connected, so a live proxy keeps serving its real connections;
put it back on its own config afterwards.
## ThermoPro advertisements as scan results (#22047, #22054)
`scripts/ble_event_inject/tpinject.hpp` holds the advertisement records from the `thermopro_ble` unit tests (TP357,
TP357S, TP393, TP960R, TP970R, TP972S, TP25, plus invalid and 13 byte probe frames) and `tpinject::inject_all()`
feeds each one to `global_esp32_ble_tracker->gap_scan_event_handler()` with the device name and the manufacturer
data, the way `scripts/xiaomi_ble` does. Frame N comes from `A4:C1:38:00:10:0N` (up to `:10`), so give each
`thermopro_ble` sensor that MAC, include the header and call `tpinject::inject_all();` from an `interval:` or a
template button. Compare the published states (or the sensor DEBUG lines) on the PR and on dev; no ThermoPro
device is needed.
@@ -1,19 +0,0 @@
# ble_midi
## BLE MIDI client against a fake instrument (#18508)
No MIDI hardware needed: `templates/ble_midi/midiperi.yaml` turns a second ESP32 (an S3 with ethernet, so the
API stays reachable while BLE is busy) into a BLE MIDI peripheral with `esp32_ble_server`: the MIDI service
advertised, the MIDI characteristic with read, write, write without response and notify, an `on_write` that logs
the bytes, buttons that notify hand built packets (channel messages, two messages in one packet, running status,
SysEx in one packet, split over two, oversize, cut short, clock, aftertouch, orphan data bytes, a 50 packet burst)
and a restart button for the disconnect test. `midicli.yaml` is the component test config on a classic devkit with
`wifi:`, `api:`, the peripheral's BLE address in the `peri_mac` substitution, given on the command line with
`-s peri_mac <mac>` (the base MAC plus 2, printed by `esp32_ble` in `dump_config`), `on_sysex` and `on_message` lambdas that print the bytes, debug sensors and out of range send
buttons. Drive both over the plaintext API with `scripts/modem/mdrive.py HOST LOGFILE press:NAME wait:S` 3 s
apart and compare the peripheral's `TX` and `RX` lines with the client's decoded lines. Gotcha:
`ble_server.characteristic.set_value` latches the value of its first play and re-applies it before every notify,
so the peripheral script sets the value from a lambda (`id(midi_io).set_value(std::vector<uint8_t>(pkt));
id(midi_io).notify();`). At VERBOSE the client logs four lines per message, so a burst shows an
`esp32_ble took a long time` of a couple of seconds that is the serial port, not the parser.
Results: https://github.com/esphome/esphome/pull/18508#issuecomment-6348272717
@@ -1,67 +0,0 @@
# esp32_ble_server pairing and encrypted characteristics (#17562)
`scripts/ble_server_security`: a classic ESP32 devkit runs the secure GATT server (`server.yaml`) and a second ESP32
(an S3 here) runs `ble_client` as the central (`client.yaml`). The server has a `read_encrypt` battery level
(`99.9`), a plain characteristic, a `write_encrypt` characteristic that logs what it receives, a `read_encrypt_mitm`
characteristic and a `read_encrypt` characteristic that notifies every 2 s. `run.sh TAG IO AUTH` builds both with the
pairing mode as substitutions, pairs once, reconnects twice, and `summary.py` prints PASS or FAIL. The server needs
`esp32_ble_server` security from #17562 or later: point `SERVER_TREE` at that checkout (the client builds from
`TREE`, dev is fine). `summary.py` needs each refused read to show an `Error reading char` reply, so a run where the
client never connected fails instead of passing.
- `ble_client` never starts pairing on its own (a phone does, after an `insufficient authentication` reply); the
client's `Pair` button calls `BLEClientBase::pair()`. Read errors show as `Error reading char at handle N, status=5`
(not authenticated: no bond) or `status=15` (not encrypted: bond known, link not encrypted yet).
- The `ble_client` text sensor subscribes once, at connect, before any pairing, so a protected characteristic refuses
it. The `Subscribe` button writes the CCCD again after pairing; `ble_client` drops its service list after discovery,
so it writes the characteristic handle + 1 (where ESP-IDF's GATT server puts the CCCD).
- Numeric comparison (`display_yes_no` with `sc_mitm_bond`) tells a fresh pairing from a bond reuse: the
`numeric comparison` line only appears on a fresh pairing. Just Works cannot show it.
- ESP-IDF 5.5.6 drops the bond on the second disconnect on both roles (`Deleting unpaired device`), so that reconnect
pairs from scratch; 5.5.5 keeps it (`-s idf 5.5.5`).
- The server keeps its bonds in NVS. One holding an authenticated bond for the client refuses a Just Works re-pairing
silently; erase the devkit's flash before switching from nc to jw.
- `summary.py` failed both modes at 58636914ab: `read_encrypt_mitm` was readable with no pairing, because
`BLEService::create_characteristic()` took an 8 bit `esp_gatt_char_prop_t` and dropped the MITM bits (1 << 8 and
1 << 9). Check the generated `create_characteristic` call and the property type when a flag above bit 7 is added.
## ESP32 central against the secure server (#17562, #22081)
`scripts/ble_server_security/esp32central-*` swaps the roles: an ESP32-S3 runs the secure server
(`esp32central-srv.yaml`: plain, encrypted, MITM read and write, and an encrypted notify characteristic, numeric
comparison accepted automatically) and a classic ESP32 devkit runs `esp32central-cli.yaml` (`ble_client` with
`display_yes_no` and `sc_mitm_bond`, text sensors that log every value, a MITM write and a link cycle every 40 s).
`bonds.hpp` logs the bond list Bluedroid loaded from NVS on both boards.
- The server never starts pairing (a peripheral only answers a security request), and `ble_client` does not start
it on an insufficient authentication reply (status 5) the way Android does. The client's `on_connect` calls
`esp_ble_set_encryption(remote_bda, ESP_BLE_SEC_ENCRYPT_MITM)` instead.
- `esp32central-flow.sh TAG` erases both boards, flashes them, captures a fresh pairing with three link cycles
(phase A), then resets both together so each loads its bond (phase B), and prints per phase the connects, numeric
comparisons (a fresh pairing), MITM reads, server writes and `Deleting unpaired device` lines. It passes when
phase B reads the MITM characteristic with no numeric comparison and no `Deleting unpaired device` line.
- On ESP-IDF 5.5.6 every other reconnect pairs again (`Deleting unpaired device` on the disconnect after a bonded
reconnect), the regression #22081 describes.
## Bluedroid hex parsing bench (#22081)
`scripts/bluedroid_hex_bench/`: `hexbench.hpp` times Bluedroid's `sscanf` parsing (`string_to_bdaddr` and the
`btc_config_get_bin` loop) against the parsers in #22081's `esp32_ble/bluedroid_hex.h` on the same inputs, valid and
invalid, and checks that the outputs match. `run.sh LABEL` (env `TREE`, `PORT`, `SC`, `PY`, `BOARD`) builds
`bench.yaml`, flashes, captures 25 s and fails on any mismatch or a missing `DONE`. Classic ESP32: about 7 to 9 times
faster for addresses, 6 to 7 times for 16 and 28 byte keys.
## ble_client on_notify with a real server (#21821)
`scripts/ble_notify/`: `server.yaml` (ESP32-S3 GATT server; a numeric and a text characteristic notify every 2 s,
with uint16 frame and empty notification rounds, set through `id(c)->set_value(...)` and `notify()` in a lambda) and
`client.yaml` (classic ESP32 client with two `on_notify` triggers per sensor, one of them delayed, and a link cycle
every 60 s). `run.sh LABEL` (env `TREE`, `SERVER_PORT`, `CLIENT_PORT`, `SERVER_BLE_MAC`, `SC`, `PY`) flashes both,
captures the client 150 s and counts `on_notify` against `on_value` per sensor.
- `run.sh` also requires `All clients established, services released`: before #21821 it never appears with a text
sensor `on_notify`. The delayed txt `on_notify` may miss only the last notify of the capture.
- The server takes one connection. Park any other client that would connect to it with
`esptool --after no-reset chip_id` (the board stays in the bootloader).
- An ESP32-C6 devkit whose native USB port refuses esptool can be flashed and logged through its UART bridge port
with `logger: hardware_uart: UART0`.
@@ -1,27 +0,0 @@
# BLE terminate with peripheral latency (#20232)
`scripts/ble_terminate`: an ESP32-S3 `bluetooth_proxy` (active) over Ethernet as the central (`btproxy.yaml`) and a
classic devkit `esp32_ble_server` peer (`btpeer.yaml`). The peer asks for 50 ms / latency 10 / 6 s with
`esp_ble_gap_update_conn_params` 4 s after connect; earlier requests are overwritten by the proxy's own "medium
conn params" after service discovery. Read the proxy's `Conn params updated` line (VERBOSE, API logs) to confirm;
the peer side never logs the event. The proxy only connects to a device its scanner has seen, so `btdrive.py`
subscribes to raw advertisements first.
Measure the peer's own disconnect (`serial_capture.py --ms`) after the client's disconnect: about 0.2 to 0.8 s when
the terminate arrived, about 6 s (the supervision timeout) when it was lost. The client side disconnect time is the
API reply and says nothing. On dev the S3 lost 6 of 12; the PR lost 0 of 16.
`run.sh LABEL ROUNDS` writes `central_bda.hpp` from `PROXY_BT_MAC`, builds and flashes both boards, runs the rounds
and `an.py`, which prints PASS only when every round completed, every peer disconnect came within 3 s and the last
parameter update the proxy logged before each disconnect had latency=10 (a round without it did not test peripheral
latency and counts as inconclusive).
Controller build check: ESP-IDF 5.5.6 ships `libbtdm_app.a` byte for byte the same as 5.5.5 for esp32c3 and esp32s3
(build 51d9dfd). Without hardware:
```bash
strings -a <idf>/components/bt/controller/lib_esp32c3_family/<chip>/libbtdm_app.a | grep -E '^[0-9a-f]{7}$'
```
On a board: a button lambda logging `btdm_controller_get_compile_version()` (declared `extern "C"`) over the API,
since the ESP-IDF init line only reaches the UART.
@@ -1,28 +0,0 @@
# bluetooth_proxy
## Held GATT link after a half-open API session (#21256, #22077)
When Home Assistant stops answering without closing its socket, the proxy must not keep the BLE link it opened for
that session. `scripts/bluetooth_proxy_half_open/` reproduces it with:
- `proxy.yaml`: the proxy under test on a classic ESP32 devkit (ESP-IDF, VERBOSE logger with the busy tags at DEBUG,
encrypted API). Build it from the tree under test with a `secrets.yaml` (`wifi_ssid`, `wifi_password`, `api_key`).
- `peripheral.yaml`: a second ESP32 (an S3 here) as a peripheral that only advertises while nobody is connected
(`esp32_ble_server` takes one client by default), with manufacturer data `FF FF 21 56` so the client can find it.
- `ha.py`: the Home Assistant stand-in (aioesphomeapi, `client_info` "Home Assistant test"). Roles: `owner` connects
to the peripheral through the proxy and idles, `observe` counts the peripheral's adverts and the slot report and can
ask for a connect at the end, `swap` connects at once and retries on the first advert. Every role stays subscribed
to advertisements: with no subscriber the proxy's loop disconnects every link at once, which hides the bug (an
early run failed with `disconnect while backend idle` for that reason).
`cases.sh PROXY_HOST LABEL` (env `PROXY_PORT`, `PERI_PORT`, `SC`, `PY`, `API_KEY`) captures both boards and runs
case C (old client killed, new client after 4 s), case H (old client frozen with `SIGSTOP`, so the socket stays open
with no FIN; new client after 4 s, watched 300 s, then it asks to connect and releases) and case N (frozen and nobody
reconnects for 200 s). `cases.sh PROXY_HOST LABEL swap` instead repeats H three times with the new client
connecting at once (`ha.py ... swap ADDR`) and retrying on the first advert. Both end with PASS or FAIL: the cases
fail when an observer exits non-zero, never sees the peripheral advertise (the held link) or the proxy resets, and
swap fails when a round never connects. An owner that never got the link also fails (a rig problem, not a result).
- The proxy drops a frozen session as unresponsive after about 144 s.
- Before #22077, case H holds the link for good: 0 adverts, and the address stays in the slot report. With #22077 the
link is released in the same millisecond as the `replaces` warning. In case 4 the first request logs `Connection
request ignored, state: DISCONNECTING` (connected=false at 0.2 s) and the retry connects at 0.5 to 0.7 s.
@@ -1,46 +0,0 @@
# buttons
Button platforms converted to `button::ApplyButton` change no behaviour on the wire, so each test compares what a
press does on dev and on the PR: the pad, the action call or the bytes sent. All three run on a D1 mini with no
wiring and no other device.
## output button pad timing (#21907)
`scripts/output_button`: two `gpio` outputs on GPIO5 and GPIO4 and three output buttons (500 ms and 1000 ms on
GPIO5, 200 ms on GPIO4). `edges.hpp` attaches a CHANGE interrupt to each output pad and stamps every edge with
`micros()`; on ESP8266 a pad reads back its own output level. A script runs four cases three times: one press, a second
press 250 ms in (the reset restarts, high 750 ms), both outputs at once, and the 1000 ms button then the 500 ms
button on the same output 300 ms later (low at 800 ms). `run.sh LABEL` flashes, captures 45 s and prints the edge
lines; diff dev against the PR. Each button keeps its own reset timer, so the 1000 ms button's reset fires later on a
pad that is already low and shows no edge.
Results: https://github.com/esphome/esphome/pull/21907#issuecomment-6516597178
## homeassistant button through a raw API client (#21908)
`scripts/homeassistant_button/ha-button-common.yaml` has three `homeassistant` buttons: `button.doorbell`,
`input_button.chime`, and one with no `entity_id` that is an `api: wizard:` input. An `on_boot` press runs before
any client connects. `habdrive.py HOST` is a plaintext API client that subscribes to Home Assistant actions, presses
each button and prints every action call (service and data). It sets the wizard input with `WizardInputSetRequest`
(message 158, key = FNV-1 hash of the input's id), first to an `input_button`, then to a `button`, then to an invalid
value the device must reject. `run.sh LABEL` flashes, captures and drives it. Expect `button.press` or
`input_button.press` per entity, `No entity ID set yet` and no call before the wizard input is set, and `No clients
connected` from the boot press.
- `homeassistant` entities are internal by default, so the client sees no buttons unless they set `internal: false`.
- Wait for each reply type instead of a fixed time: the hello reply can take more than a second, and a fixed wait
shifts every later reply by one step.
- Results: https://github.com/esphome/esphome/pull/21908#issuecomment-6516693220
## uart button on the UART0 loopback (#21906)
`scripts/uart_button/uart-button-common.yaml` puts four uart buttons on UART0 of a D1 mini: a 10 byte string, five
raw bytes with `0x00` and `0xFF`, the same string again (shares one generated function on the PR), and 64 bytes. It
sets the UART0 loopback bit in `on_boot`, so every press comes back on RX, and `uart: debug: direction: BOTH` logs
both sides. `run.sh LABEL HOST` flashes by USB and runs `ubdrive.py`, which presses each button 3 times over the API
and saves the log. Every `>>>` line must equal the configured payload and its `<<<` line.
- Set the loopback bit at `on_boot` priority -100. At 800 the UART setup runs afterwards and clears it.
- Nothing else reads the bus, so the debugger needs `dummy_receiver: true` to log RX.
- UART0 is the bus, so `logger: baud_rate: 0` and logs go over the API. The device address comes from DHCP or mDNS.
- An RX line sometimes lands after the next press marker when the log stream lags. That is not a byte difference.
- Results: https://github.com/esphome/esphome/pull/21906#issuecomment-6516762337
@@ -1,21 +0,0 @@
# captive_portal
## Captive portal `/wifisave` hammer (#20802, #20784)
Reproduces a `/wifisave` arriving during the STA cooldown, and proves a fix on every board.
Device under test: `templates/example-dut.yaml` (bogus network, `ap:` with `ap_timeout: 15s`,
`captive_portal:`). Client: `templates/example-client.yaml` on an ESP32 or a D1 mini; it joins the
device's AP, posts 15 bogus saves 3 s apart, then the real credentials. With the portal up the cooldown
is 30 s, so nearly every save lands inside one. Driver: `scripts/wifisave_hammer.sh`. Settle 40 s on
ESP boards, 90 s on the BW15 (its first attempt on the real network fails, see boards.md).
Counts that matter: `Requested WiFi Settings Change` (saves received), `Exiting cooldown early`, crash
markers, boots (`Log initialized`), and the client's `bogus save status 200` and `real save status 200`.
A healthy run: every save answered 200, one cooldown exit per save (two on the BW15, whose retry enters
the adapter restart), no panic, and the real credentials connect the device within about 10 s.
Fault injection for AP start failures: wrap `this->ap_setup_ = this->wifi_start_ap_(this->ap_)` in
`setup_ap_config_()` with an `HWTEST_AP_FAIL_COUNT` build flag
(`esphome: platformio_options: build_flags: -DHWTEST_AP_FAIL_COUNT=2`), raise the portal's "Captive
portal started" from LOGV to LOGI, and after provisioning curl the device's STA address: connection
refused proves the portal's server is gone.
@@ -1,26 +0,0 @@
# Crash report over the API (#21596, #22288)
#21596 lets an API client fetch the crash recorded on the previous boot; #22288 records `abort()` as a crash on
LibreTiny. `scripts/crash_report/crash-common.yaml` (a package: Wi-Fi from `secrets.yaml`, plaintext API, OTA,
DEBUG logger) adds three buttons: `crash abort`, `crash null store` and `crash div zero`. The per-run file supplies
the board and the name. Flash it, then run the drivers (they import `scripts/apiconn.py`, so run them in place or
put `scripts/` on `PYTHONPATH`):
- `drive.py HOST BUTTON_OBJECT_ID` (for example `crash_abort`) reads the capability, presses the button, reconnects
after the reboot and fetches the report twice (reason, PC, cause, fault address, build time, per-core backtrace),
subscribes to logs with `dump_config` to see what is replayed, and checks the capability from a second client.
It reads an earlier report first, so a stale one cannot pass. It exits 1 when the device still answers after the
press, does not offer a report after the crash, or the report has no reason or a PC of 0.
- `peek.py HOST` prints only the capability and how many replayed `CRASH DETECTED` lines a new log client gets. To
only press a button, use `scripts/api_button.py HOST - press "crash abort"`.
- Decode the PC and the backtrace with the build's ELF (`addr2line -e firmware.elf`). On RTL8720C a noreturn
`bl abort` can be the last instruction of a function, so the return address points at padding: decode
`(addr & ~1) - 2` to get the call line.
- `__builtin_trap()` faults on every board. A store to `nullptr` does not fault on every chip (BK7238 and RTL8720C
ignore it), so the `crash null store` button proves nothing there.
- With #22288, `abort()` reboots BK7238, RTL8720C and LN882H boards in 1 to 2 s and logs `Reason: Abort` with the PC
at the call site. Before it, the BK7238 hangs until reset, the RTL8720C restarts with no record and the LN882H
waits about 18 s for its watchdog.
- Quick crash reboots count toward BK72xx safe mode, so space out back-to-back crash tests on those boards.
- A device that keeps the previous crash replays it to every new log client until the next crash; that is one
record, not two.
@@ -1,11 +0,0 @@
# cse7766
## cse7766 on a Sonoff S31 (#20948)
`templates/s31-cse7766-dut.yaml`: `logger: baud_rate: 0` because the CSE7766 owns the UART, VERBOSE logger
with everything but cse7766 quieted, 2 s throttles, and a `globals` frame counter fed by the voltage sensor's
`on_raw_value` and logged every 10 s (about 96 frames per 10 s). OTA only, every reflash reboots the relay.
`scripts/cse7766/run_obs.sh IP SECONDS LABEL [OUTDIR] [NAME_FILTER]` subscribes to states and logs over the
API with a concurrent ping and prints the frame counter, API gaps and warnings. API state gaps of 10 to 20 s
can appear on a weak Wi-Fi path while the device counter stays flat, so judge a UART parser by the
device-side counter, not by the API cadence. With nothing plugged in, current and power read 0.
@@ -1,21 +0,0 @@
# dfrobot_sen0395
## DFRobot SEN0395 mmWave on an ESP32 DevKit V1 (#20906, #20979)
Wiring: V to VIN (5 V, the module wants 3.6 to 5 V), G to GND, sensor TX to GPIO16 (RX2), sensor RX to GPIO17
(TX2), IO2 to GPIO18 (presence output, a gpio binary sensor), I1 unconnected. `templates/dfrobot-sen0395-dut.yaml`
has the hub, both detection binary sensors, the four switches, settings buttons and junk-line buttons.
`scripts/dfrobot_sen0395/ctl.py HOST KEY press:NAME sw:NAME=on|off wait:S` drives it and prints binary sensor and
switch updates; `cases.sh DEV_IP KEY CAPTURE LABEL` runs the whole flow against a running serial capture. Flash by
USB, `serial_capture.py PORT 540 CAPTURE --reset`, then the cases; compare the `Sending command` and `Message:` lines
and the counts of `Done`, `Error`, prompts and frames between builds. The module echoes every command, so the echoed
lines are the bytes the component sent and can be compared between builds as a set.
Module facts: it answers `Done` or `Error` and then the `leapMMW:/>` prompt without a line end; a junk line gets
`<line> is not recognized as a CLI command` (36 chars longer than the line, so 220 and 240 byte junk gives 256 and
276 char replies); input lines of 256 bytes or more make the module assert (`..\User_code\main.c line:232`) and
restart, after which the sensor is stopped; a factory reset restarts the module about 7 s later; `sensorStop` on a
stopped sensor answers `sensor stopped already` then `Error`; a settings press takes 5 to 6 s (stop, change, save,
start). Free heap on the ESP32 is Wi-Fi noise (192 to 198 kB) and says nothing about the component.
Results: https://github.com/esphome/esphome/pull/20979#issuecomment-6279129146 and
https://github.com/esphome/esphome/pull/20906#issuecomment-6279129604
@@ -1,7 +0,0 @@
# espnow
## ESP-NOW on the ESP8266 (#14407)
The NONOS SDK only delivers broadcast ESP-NOW frames while the station is associated or a soft-AP is
up; a hidden, open, client-less soft-AP (60 s beacon, DHCP stopped) makes broadcasts arrive. In AP-only
mode the device transmits from the soft-AP MAC.
@@ -1,37 +0,0 @@
# EZO circuits without hardware: a fake I2C bus (#21840)
`scripts/ezo_fake_bus`: the real `ezo` component runs on a classic ESP32, but an `on_boot` priority 900 lambda calls
`id(ph).set_i2c_bus(&fakeezo::bus)`. `fake_ezo.hpp` is an `i2c::I2CBus` subclass that answers like an EZO pH circuit
and logs every write and read with the ms since the command: `R`, `i`, `Slope,?`, `Cal,?`, `T,?`, `L,?`, `Name,?`,
and test replies `pend` (254 twice), `bad` (2), `nodata` (255), `nak` (read NACK) and `full31` (32 bytes with no
terminator), and `sNN` (an NN-character reply, terminated when the read has room). `ezo.yaml` runs the steps:
command bursts larger than the queue, custom commands, calibration, LED, sleep and address changes, and the error
replies.
- The same trick works for any I2C device whose driver only needs write and read: swap the bus pointer, no wiring.
A real `i2c:` block is still needed so the config validates.
- `run.sh LABEL` builds, flashes, captures 90 s and writes `out-ezo<LABEL>.events`. Compare dev and the PR: the
replies, callback texts, read values and the wait before each read (912 ms for reads and calibration, 304 ms for
the rest) must match; differences in queue limits are the PR's intended change.
- Call plain `millis()` in a fake: Arduino builds define a `millis()` macro (`esphome::millis()`), so
`esphome::millis()` breaks there, and on ESP-IDF the plain name resolves through `using namespace esphome`.
- Found with it: dev read past its 32-byte buffer on an unterminated reply (a custom callback got 56 bytes), and
two queued address changes both went to the first new address.
- Results: https://github.com/esphome/esphome/pull/21840#issuecomment-6493565259
## Trigger argument lifetime (StringRef or an owning copy, #22204)
Give each text trigger two automations (`- then:` list items): a synchronous one that logs `x`, `x.size()` and
`strlen(x.c_str())` and hands `x` to a parallel `script` (`text: !lambda return x;`, the script delays 2.5 s), and
one with `delay: 3s` or `wait_until` that logs `x` afterwards. Fire bursts so newer replies reuse the reply buffer
during the wait, then diff the synchronous texts, in order, against the delayed and script texts. Check the generated
`main.cpp` for `StringRef` or `TriggerForwarder<std::string>`. The fake's `sNN` replies give texts of any length.
## A real EZO circuit
An EZO-HUM ships in UART mode (blinking green, streams `33.91\r` every second at 9600 baud). To switch it to I2C
without bridging PGND, flash a one-shot software UART build (TX to the EZO RX, RX from the EZO TX) that writes
`I2C,111\r`; the LED turns blue and the circuit answers at 0x6F. Replies: `i` gives `HUM,1.01`, `Status`
`?STATUS,S,3.31`, `O,?` `?O,HUM,T,DEW`, and `R` with all outputs `34.82,22.03,Dew,5.85`; `Name,x` returns no text.
EZO-HUM rejects `T,?`, `Slope,?` and `Cal,?` (syntax error), so `on_t`, `on_slope` and `on_calibration` need another
circuit or the fake bus. Log every callback with an `EV` prefix and count them per step.
@@ -1,153 +0,0 @@
# Fake I2C devices without a chip
## Fake devices on an in-firmware I2C bus
When there is no chip and no wiring, subclass `i2c::I2CBus` in an include, implement `write_readv()` only, answer
the registers the driver reads and check each write. Point the component at it from an `on_boot` lambda that runs
before the component's `setup()`: `id(x)->set_i2c_bus(&fake::bus)` at priority 950, which is ahead of every I2C
component (hubs set up at IO, 900, sensors at DATA, 600). The configs here that use 700 to 1000 work for their
components; use 950 for a new one. Keep a real `i2c:` block in the config so validation passes. Bulk
loops in a button lambda must call `App.feed_wdt()` and keep their per-iteration logs below INFO: 2000 DEBUG lines at
115200 baud trip the task watchdog, which is a fault of the harness and not of the PR.
`templates/i2c_fake/` holds the fakes; each `*-common.yaml` or `*-test.yaml` is a classic ESP32 or ESP32-S3 config
that includes its `.hpp` (add `esphome: name:` for the `-common` ones):
- `ccsfake.hpp`, `ccs-common.yaml`: CCS811 at 0x5A (#21927). Answers setup and update reads and checks every
ENV_DATA write against the humidity and temperature the case set; "CCS Cases" runs edge values, "CCS Sweep" 2000
random ones and logs `SWEEP checked N bad M bad_reads R bad_writes W`. A read without a register, of a register
the fake does not model or of the wrong length gets a NACK and counts in `bad_reads`; a write other than the
driver's SW_RESET, APP_START, MEAS_MODE and BASELINE writes (each with its own length) gets a NACK and counts in
`bad_writes`. The CASES and SWEEP lines end in PASS only when something was checked and `bad`, `bad_reads` and
`bad_writes` stayed 0, and in FAIL otherwise.
- `eefake.hpp`, `ee-common.yaml`: HTE501 (0x40) and TEE501 (0x48) with CRC words; "Next" steps through raw
temperature words and logs the value a signed hundredths decode should give (#21930). A command other than
identification and measure, and a read longer than the reply, gets a NACK and counts as `bad`. The DONE line
200 ms later, after both reads, shows the running `bad` total, the measure replies each driver read and the
published values; it ends in PASS only while `bad` is 0, both drivers read a reply this case and both published
the expected temperature (and HTE501 the fixed humidity).
- `scdfake.hpp`, `scd-common.yaml`: SCD4x at 0x62 and 0x63 with Sensirion CRC; logs every `0xE000` ambient pressure
write, and the CASE and SHOW lines count writes with a bad CRC apart from the good ones. A command the scd4x driver
does not send, one sent with the wrong length (2 bytes bare, 5 bytes with one CRC word), or any other command with a
bad CRC, gets a NACK and counts as `bad writes`. A read after a command the fake does not answer, or one longer than the command's
reply, gets a NACK and counts as `unknown reads`. The second instance has a fixed `ambient_pressure_compensation`
to cover the setup path (#21935). Each CASE line ends in PASS only when bad CRC, bad writes and unknown reads did
not move, the `0xE000` writes match `expect_e000()` (none, or one with the expected value) and, for a source case,
CO2 was published. `RANGE_CHECKED` in `scdfake.hpp` picks the rule: false truncates as dev does, true skips values
outside 700 to 1200 hPa and rounds as #21935 did. The SHOW line ends in PASS when nothing bad was counted, neither
instance failed and 0x63 got exactly one write of its fixed value.
- `sxfake.hpp`, `sx-common.yaml`: two SX1509 register files with reset values and the `7D 12/34` reset, recording
every write. Only a byte that lands on RegReset (0x7D) drives the reset, so a burst through it keeps the bytes for
0x7E and 0x7F. A read without a register, or a transfer past 0x7F, gets a NACK and `dump_log()` warns with the
count. Compare per address: hub setup order can legitimately move between hubs (#21897). Outputs of an Apply
platform are distinct template types, so a lambda list of them needs
`std::initializer_list<output::FloatOutput *>{...}`. Each case ends with an END line, PASS only while no write was
dropped and no transfer was bad; the writes themselves are judged by the diff.
- `msfake.hpp`: eight MS8607 pressure/temperature fakes at 0x76 and up and humidity fakes at 0x40 and up, with faults
per device (reset NACKs, bad PROM CRC4, zero D1 every Nth read, humidity CRC8 errors, out of range D2, full scale
humidity). It counts every command, so skipped conversions show in `report()`, and an ADC read with no conversion
pending answers 0 like the real chip and counts as `adc_no_conv`, and a humidity read with no measure pending gets
a NACK like the real chip in no-hold mode and counts as `read_no_measure` (a reset aborts either); each injected
fault counts when it is delivered (`inj_reset_nack` with `reset_nack_left`, `inj_zero_d1`, `inj_bad_crc`), so a
run that never reached a fault path shows 0 there; a PROM read, conversion or humidity measure
before that device's first reset counts as `no_reset`; a humidity read of any shape but a bare
3 byte read, and a pressure/temperature read that is not a 2 byte read of a PROM word (even addresses 0xA0 to 0xAC) or
a 3 byte ADC read, gets a NACK and counts as `bad_reads`; a bare read answers the last PROM or ADC pointer and never
repeats a reset or conversion; a command write the fake does not know, or one longer than a
byte, gets a NACK and counts as `bad_cmds`. Point both the component and its `humidity_i2c_id` device at the bus. That
driver logs no values, so give each sensor an INFO `on_value` log (#16487).
- `htfake.hpp`, `ht16k33-char-test.yaml`: HT16K33 chips at 0x70 to 0x77 (0x74 and 0x76 NACK) keeping the 16 byte
display RAM and a command trace, rendered back as text for the Adafruit 0.56" 7-segment backpack ("12:34",
decimal points, "!" for stray bytes); a read gets a NACK and counts as malformed. The test runs 64 checks (setup order, font, colon and dots, chained chips,
printf/strftime/clock, dimming, blink, standby, NACK) and ends with `ALL DONE pass=N fail=M` and PASS or FAIL (#8520). It found a
crash (null glyph table) when one display had `add_characters` and another did not.
- `ssfake.hpp`, `seesaw-test.yaml`: Adafruit seesaw at 0x36 (ATtiny817), 0x49 (SAMD09) and 0x4A (NACK): status,
GPIO bulk with the pull latch, ADC, touch, encoder and NeoPixel with chunk offsets, and the write to read gap per
module. A read it does not model, a write without a register and a write to a module or register it does not model
(or with the wrong data length) get a NACK and count in `bad`. A 100 ms interval step machine drives it and ends with `ALL DONE` and PASS or FAIL (#13538).
- `bldcfake.hpp` (three M5Unit-BLDC units at 0x65 to 0x67 with simple motor physics, one that never spins down),
`gtfake.hpp` (GT911 at 0x5D: switches, max values, touch points and key byte) and `sdpfake.hpp` (SDP3x/SDP8xx at
0x21 to 0x26: product IDs, an unknown product, a failing read every third time, a failing ID read, stop refused
while idle) have no config yet; wire them the same way. Each fake sets up its own faults in its constructor, so
there is no init step to call. Each NACKs a read it does not model or one of the wrong
length, and a write or command it does not know, and counts them as `bad_reads` and `bad_writes` (`bad_cmds` for
the SDP) in `report()`; check those are 0. The SDP report also counts each injected ID read NACK at 0x24 as
`id_fail`, so 0 there means the driver never reached that fault.
Check the PR head again just before posting results: a head that moves during a run means a retest.
## Pico 2 W as an I2C target (#22236)
`scripts/pico_i2c_target/`: `picofake.hpp` is a raw RP2350 I2C0 interrupt handler on GP4 (SDA) and GP5 (SCL) at 0x76 that
answers one byte per read request from a 256 byte register file, so any read length is byte exact. `picofake.yaml`
plays a BME280 (`chip_id` 0x60) or BMP280 (0x58) with the datasheet calibration; every 15 s it switches between the
datasheet example readings and the 0x80000 "no measurement" values, and logs `STAT` counters every 5 s. `bad`
counts reads and writes of registers the drivers do not use (soft reset only with 0xB6, read pointer wrapping past
0xFF). The DUT is
an ESP32-C3 (`dut-common.yaml`, GPIO6/GPIO7) with two sensors on the one fake (`dut-bme280.yaml`,
`dut-bmp280.yaml`), the second with oversampling NONE. `run.sh bme280|bmp280 LABEL` flashes the DUT, starts the
fake capture and waits for a `STAT` line as the baseline, then resets and captures the DUT and prints the distinct
values per sensor. The fake capture runs on until a `STAT` line arrives after the DUT capture ends, so that line
covers the whole run. It prints PASS when every sensor gave a numeric state, that `STAT` line came, and the fake's
`abrt` (read replies the controller aborted) and `bad` counts did not move from the baseline; diff the output of dev
and the PR.
The ESP32-S3 I2C slave v2 driver cannot emulate a register device: answering from a task and straight from the ISR
both gave shifted multi-byte reads. Use the Pico.
## DS2482-800 simulator (ds248x)
`scripts/ds248x_sim/`: `dssim.yaml` with `sim.hpp` turns a Pico 2 W into a DS2482-800 at 0x18 (GP4 SDA, GP5 SCL)
with four DS18B20s: channel 0 at 21.5 °C, channel 1 at 33.0 °C, channel 2 at -5.25 and 40.0 °C. The DUT is an
ESP32-C3 (`dspd.yaml`, GPIO4/GPIO5 plus GND); the internal pull-ups are enough at 50 kHz. Faults are one character
on the Pico's USB console: `c` NACKs the read pointer write after the next channel select, `z` NACKs the 9 reads
after the next 0xBE, `b` and `k` stick busy with a failed reset or config write, `x` and `X` make it dead and alive.
`SC=<serial_capture.py> python3 drive.py TAG SIM_PORT DUT_PORT [c,cd,z,b,k,dead]` (default `c,z,b,k,dead`; `cd`
runs the `c` fault densely, 28 times about 3 s apart) resets the DUT per phase and prints
readings, wrong values, log counts and the simulator's counters (`wrong_ch` counts ROM matches on the wrong
channel). The DUT is captured with `--ms` so the log can be split at the last fault: the recovery window starts
`SETTLE` (3) seconds after it. A phase fails when any of the four sensors got no correct reading in the recovery
window, the DUT logged a CRC, held low, busy timeout or no response line in it, a temperature is wrong, a phase other
than `dead` logged `recovery failed`, `DS248x hub failed` or a component marked failed, a ds248x warning is still
set at the end of the phase, the DUT capture
failed (stderr in `TAG-<phase>.err`), a fault moved its injection counter (counted when the DUT meets the
fault, not when it is armed) by other than the number of faults sent (`arm_lost` counts arms that landed while one
of the same fault was still pending and merged into it), a NACK fault never moved `nacked`, a write delivered data while a NACK was armed
(`nack_miss`, also counted when the write is followed by a repeated start into a read; the NACK never reached the wire and stays pending), the DUT sent an address-only write (`empty_wr`), a write was cut off by a repeated start into another write and
never processed (`dropped`),
a fault is still pending (`pend=1`) at the end of the
phase, the simulator counted a config write with a wrong complement (`cfg_bad`) or an unknown, short or overlong
command (`bad_cmd`), a counter is missing from the simulator's CNT line, the simulator aborted a read reply
(`tx_abrt`, not gated in the `dead` phase, which switches the controller off), a phase other than `b` and `k` (which
reset the chip under the driver) counted `wrong_ch` or a 1-Wire command without the active pull-up bit (`ops_no_apu`),
the simulator never logged `DEAD` for the `dead`
phase, or the DUT log of the `dead` phase has no sign of the outage (`did not respond`, a ds248x warning,
`DS248x hub failed` or a component marked failed). It ends with PASS or `FAIL:` and the failed phases. The whole
phase CRC, held low, busy timeout and no response counts are printed for information: the faults cause them.
- Sensors polled at the same interval go through the channels in blocks, so a stale channel cache never shows.
Poll them at different intervals, as `dspd.yaml` does (1, 1.3, 1.7 and 2.3 s).
- The NACKs use the RP2350 `slv_data_nack_only` register, set at STOP.
- A NACKed write and an address-only write both end with no data, so the simulator cannot tell them apart.
The ds248x driver never sends one, `dspd.yaml` sets `scan: false` and the simulator only sees STOPs after its
own address, so `empty_wr` (address-only writes outside a NACK window) stays 0; a nonzero count means `nacked`
may include writes that never carried a NACKed byte.
## I2C fault injection in software (vl53l0x)
`scripts/i2c_fault/`: `faultbus.h` wraps the real `I2CBus` and returns NACK for chosen transfers to one address. An
`on_boot` priority 800 lambda swaps the sensor's bus (`id(d)->set_i2c_bus(&fb)`) before its setup, and an interval
arms the faults. `vlpf.yaml` runs a VL53L0X on an ESP32-S3 (GPIO8/GPIO9) through quiet, fault A (the next
measurement-in-progress read fails), quiet, fault B (the next measurement start fails) and quiet phases over 150 s,
with a model ID probe every 10 s to tell a driver stall from a dead chip. `run.sh LABEL` builds, flashes, captures
and runs `an.py`, which counts readings per `PHASE` line. Each `PHASE` line clears a fault that was armed and has
not fired yet and logs the fired totals so far, so `an.py` counts the fires of each phase. It fails when the phases are not quiet, faultA, quiet,
faultB, quiet (a short capture or a restart), the first quiet phase has no readings, a later quiet phase reads less
than half as often as the first, a later quiet phase reads NaN (`nan` or `-nan`) or logs the driver's "update called before prior
reading" warning when the first did not (a target out of range reads NaN in every phase), a quiet phase has a failed
model ID probe, one that did not return 0xEE or no successful probe at all,
anything crashed or rebooted, or a fault did not fire in its own phase or fired in another one.
Prefer this to glitching the wire. Holding SDA low by rerouting the pin (`esp_rom_gpio_connect_out_signal` to
`SIG_GPIO_OUT_IDX` and back to `I2CEXT0_SDA_OUT_IDX`) wedges the ESP-IDF controller, which then needs
`i2c_master_bus_reset()` after each glitch, and glitches timed onto writes left the VL53L0X answering 0x00 until a
power cycle.
@@ -1,15 +0,0 @@
# globals
## Restoring globals with storage: rtc and flash (#13954)
`templates/globals-storage-dut.yaml` is the shared package: five restoring globals (rtc int, flash int, default int,
rtc `std::string`, rtc `uint8_t[2]`), bumped and logged with the reset reason on every boot, saved and synced after
2 s, odd boots `App.safe_reboot()`. Platform files add the board (`packages: dut: !include globals-storage-dut.yaml`), the `debug` reset-reason text sensor and, on the
ESP32, `deep_sleep: run_duration: 12s, sleep_duration: 8s` (even boots sleep). No network needed: flash by USB,
`serial_capture.py PORT 110 OUT --reset` gives the reset pulse plus a run of soft restarts and sleeps; the ESP32's
EN pulse is a `POWERON_RESET` that empties RTC memory, the D1 mini's RST pulse (`rst cause:2`) keeps it, so the
ESP8266 needs a real power cut by hand; arm long `--released` captures on both ports first (the capture
reopens the port when it comes back, the very first boot lines are still lost, read the next boot's restored
values). Unchanged-build check: the config with every `storage:` removed, built on the PR and on the dev merge
commit under the PR's own commits (not the merge base, which is older dev), `cmp -l` plus an `nm -S` symbol diff;
only the template names differ. Results: https://github.com/esphome/esphome/pull/13954#issuecomment-6254794712
@@ -1,13 +0,0 @@
# GPIO expanders
## Interrupt driven base class (#21469, #21468)
Any device with a PCF8574 input expander whose INT line goes to an ESP32 GPIO works; the inputs should change
during the test (end switches on a gate or cover are ideal). Before flashing, check with `nm` that
`gpio_expander::interrupt_pin_isr` lands in IRAM (0x4008xxxx on a classic ESP32). Then confirm `dump_config` lists
the interrupt pin and the input states match reality, and that the `pcf8574` entry is absent from the runtime stats
while idle (its loop is disabled). Drive the inputs (for a cover, `cover_command(position=1.0)` and then `0.0` over
the API, waiting for each end state): every input edge should log, `pcf8574` should show a small count in that
minute's stats and vanish in the next. For a device that cannot be reached physically, boot the same code on a
bench board first and keep a merge base image built as the fallback; an ESP32 bootloader without rollback support
leaves only `safe_mode` to recover a bad image.
@@ -1,17 +0,0 @@
# ESP32 GPIO hold through the ISR pin API (#21576)
`scripts/gpio_hold/hold_test.hpp` builds `ESP32InternalGPIOPin`s by hand, calls `to_isr()` and reads each pad back
with `gpio_get_level`: 20 ISR writes, a raw `gpio_set_level` control (a held pad must not change, an unheld one must)
and ISR `pin_mode` pulls (input must drop to `NONE` between pull changes, because the ISR path only applies pulls when
`FLAG_INPUT` toggles). It needs no wiring: unconnected pins read the pulls. Each pin runs held and unheld, then the
round logs `ROUND n PASS failures=0` or `FAIL`.
- `USE_GPIO_HOLD` comes from any pin with `hold_state: true`, so the configs add a `gpio` output on a spare pin.
- `gpio-hold-esp32.yaml` (classic devkit) runs three rounds 5 s after boot and has a `rerun` button;
`gpio-hold-esp32s3.yaml` (Waveshare ESP32-S3-ETH, where most pins go to the W5500, TF card, camera, WS2812 or
USB) runs a round every 15 s.
- C3: ESP-IDF 5.5 has `SOC_RTCIO_PIN_COUNT` 0, so `rtc_gpio_is_valid_gpio()` is false on every pin and only the
digital hold path runs.
- C6 (Waveshare ESP32-C6-GEEK, native USB): LP pads GPIO0 to 7 are RTC IO with hold. GPIO1, 2, 7, 20, 23 read high
and GPIO6 low whatever the pull (LCD, TF card or resistors); clean pins are 0, 3, 4, 5, 18, 19, 21, 22. Dev
already holds LP pads through `gpio_hal_hold_en`, so the PR and dev look the same there. H2 is untested.
@@ -1,9 +0,0 @@
# hdmi_cec
## HDMI-CEC two-board wire (#9189)
Two boards on one wire: promiscuous mode, a 0x8F request answered with 0x90 0x00, a `destination:`
filter on the reply handler, template buttons for each target plus lambdas calling
`send(source, dest, span)` as another initiator. Healthy numbers: device-side turnaround 15 to 22 ms,
round trip 144 to 156 ms. Press buttons over the API; judge timings from device logs (ESP32 light sleep
lags the press).
@@ -1,47 +0,0 @@
# homeassistant
## homeassistant light platform against a local Home Assistant (#11354)
A local Home Assistant dev install (`hass -c config`, https://127.0.0.1:8123 with a self-signed cert); its ESPHome
entries and entity ids are in `config/.storage/`. Two ESPHome RGBCW bulbs with a plaintext API are the lights, so an
"HA side" change is made directly on a bulb with `scripts/homeassistant_light/bulb.py BULB_IP - on|off|state|restart`.
Add the test devices to HA by hand with the shared `api_key` and "Allow the device to perform Home Assistant actions".
`templates/homeassistant-light-dut.yaml` is a package: two mirrors, buttons for each change, a "Log state" button, a
30 s alive line, an `on_boot` `light.turn_on` for the change-before-first-write path, and VERBOSE logging with the
noisy tags at DEBUG (a tag cannot exceed the global level). A platform file sets the board and includes it:
```yaml
esphome:
name: ha-light-dut
esp32:
board: esp32dev
framework:
type: esp-idf
packages:
dut: !include homeassistant-light-dut.yaml
```
Flash by USB, start a bounded `esphome logs` capture per device, then press buttons with
`scripts/api_button.py DEV_IP KEY press "Button"` and read the bulb with `bulb.py`. Cases: each
button against the bulb and the device log; a direct bulb change that both mirrors follow; restart the bulb, send a
change, expect the 5 s `did not report the change back` and the fallback (with an off and with an on last report);
OTA reboot with a serial capture running to see the boot-time change (the API log client reconnects too late).
Lessons: the light core clamps mireds to the range HA reported; a flash sends nothing; a change sent while HA is
connected but not yet subscribed is dropped by the api server (`client has not subscribed to actions (yet)`); after a
fallback to an off report the mirror keeps the unsent brightness; a mirror that never saw its light on since boot has
no levels to restore. Results: https://github.com/esphome/esphome/pull/11354#issuecomment-6253630336 and
https://github.com/esphome/esphome/pull/11354#issuecomment-6254161409
## Held report versus a later call (#21144)
A report that arrives during a transition is held and applied when the transition ends, unless a call came after
it. `scripts/homeassistant_light/heldcase.py DEV_IP KEY BULB_IP same|many [BULB_KEY]` (a key of `-` is plaintext) keeps one API connection to the mirror
device and one to the bulb so the steps land inside a 3 s fade: press "A 50 fade 3s", 0.7 s later set the bulb to
90% directly (the report is held), 1.4 s in press the same fade again (or "A many calls", 16 calls in one loop
pass). Pass: the mirror and the bulb end at the second call's target. Only `same` reproduces the bug: a build
without the fix logs `Applying the report that arrived during the transition` and the bulb stays at 90%. `many`
ends at 100% on both builds because the last call's target differs from the held report, so it is a regression
check only, not a reproduction. Separate button presses are too slow (about 1.5 s each) to land inside the fade.
The mirrors are not API entities, so read their state from the "Log state" button's line. Results: https://github.com/esphome/esphome/pull/21144#issuecomment-6278257695
@@ -1,48 +0,0 @@
# http_request
## Update manifest URL changed at run time (#21373)
`scripts/http_request/manifest_server.py PORT [DELAY]` serves `stable.json`, `beta.json` and `slow.json` (answered
after DELAY s) with both chip families and logs every request. `templates/http_request_update/upd-common.yaml`
(secret `manifest_base` is the server URL) has the update entity on the stable manifest, buttons for every
`set_source_url` shape (`std::string` local, literal, temporary, `.c_str()` of a local, the current URL back in),
`Check Then Swap` (ESP32 task path: check the slow manifest and replace the URL in the same lambda), `Arm Swap In
Check` plus a `logger: on_message` lambda that replaces the URL from inside the inline check (ESP8266; the log line
from inside `on_message` is swallowed, judge by the next check's result), and a `Heap` button. `upd-base-common.yaml`
keeps only the shapes that compile on a tree with the bare pointer setter (for the base build, copy a board file
and point its `common` include at `../upd-base-common.yaml` with a different `name:`); `boards/upd8266.yaml` and `boards/upd32.yaml` are the
per-board files, one directory below the package their `../` include points at. Drive with `scripts/http_request/updrive.py HOST KEY LOGFILE press:NAME wait:S`, which prints every
update state (latest version, summary). The ESP8266 Arduino client gets `Error reading manifest: -1` on roughly a
quarter of the fetches from this Python server on every build, so count checks against the base before blaming a
PR. `http_request` on the ESP8266 needs `verify_ssl: false` even for plain http URLs.
Results: https://github.com/esphome/esphome/pull/21373#issuecomment-6337544933
## Non-blocking request actions (#21486)
`scripts/http_request/hsrv.py PORT` serves `/fast`, `/slow?d=S`, `/big` and `/chunked` (`n` bytes at `rate` B/s,
deterministic bytes `(i*7+3)&0xFF`), `/post` (echoes length and byte sum), `/redirect` and `/hang`.
`templates/http_request_action/hr-common.yaml` (substitutions `name`, `bufsize`; per-board files `hr32.yaml` and
`hr66.yaml`, `-s name hr32base` on the command line for the base build; `hrota32.yaml` adds the `otaflash` action
for `otadrive.py`) has API actions `req_get`, `req_post`, `burst` (N runs of a `mode: parallel` script on one action),
`cancel` (`mode: single` script run twice, then `script.stop`) and `reboot_during`, and logs
`RESULT n status len sum took maxgap`, where maxgap is the longest main loop gap during the request (an
`interval: 1ms` lambda plus the time since its last pass, so a fully blocking request counts too). Drive with
`scripts/http_request/hrdrive.py IP http://HOST:PORT LABEL [https]` (`ONLY=case,case` and `ROUNDS=n` env; the
`cross` case runs two actions on one component). `burstonly.py IP URL N` checks concurrency against the server's
completion times, `reboottest.py IP URL` times `App.safe_reboot()` with requests in flight, `updcheck.py IP LABEL N`
runs N update checks over the API (for real device configs that use `update: platform: http_request`) and
`otadrive.py` triggers `ota.http_request.flash` (the API variable is `sum`; `md5` is a reserved variable name).
`execute_service` must be awaited on current aioesphomeapi or nothing is sent. Keep the ESP32 `bufsize` at 32 KB or
less: the action copies the body into a `std::string` while the buffer is still held, and 80 KB aborts with out of
memory on dev and on the PR alike. `http_request` refuses BK72xx and RTL87xx at validation.
## OTA request cases with basic auth (#21556)
`scripts/http_request/ota_auth/`: `ho-common.yaml` (API actions for `ota.http_request.flash` with `md5_url`, `md5`
and basic auth, `flash()` with no URL, an invalid URL, the `md5_computed()`/`md5_expected()` getters), `fwsrv.py`
(serves a www dir, `/auth/` needs `otauser:otapass`), `hodrive.py` (11 cases, reconnects after each good flash) and
`run.sh BUILD BOARD` (compiles from `TREE`, serial flash, serves that exact image; `TREE`, `P32` or `P66`, `SC` and `HOST_IP` in
the environment). On the D1 mini the authenticated MD5 read fails
with `Error reading MD5: -1` on dev too, and stored credentials carry over to the next flash on both builds.
Results: https://github.com/esphome/esphome/pull/21556#issuecomment-6381067561
@@ -1,26 +0,0 @@
# HTTPS on web_server_idf (#22185)
#22185 adds an HTTPS developer API to `web_server_idf` with no YAML option, so `scripts/https_idf/` brings a test
component: `ext/httpstest` (`httpstest.hpp`) serves `/hw` (a status line with mode, request count and free heap),
`/hw/big` (16 KB) and `/hw/switch/{http,https,https8443,bad}`. A switch runs on the main loop through `defer()`, or
3 s later with a `/later` suffix (a stalled TLS client holds the server task, so its switch is armed first), and
calls `set_ssl_credentials(cert, key, port)`: plain HTTP on 80, HTTPS on 443 or 8443, or a key that does not match
the certificate. Its schema uses `web_server_idf.consume_ssl_sockets`. The run-time switch is the follow-up API; on a
tree that only has #22185, drop the switch paths and set the credentials once before `init()`.
Copy the directory into a scratch directory with a `secrets.yaml`, then `run.sh LABEL` (env `TREE`, `PORT`, `SC`,
`PY`): it runs `make_certs.sh` (a self-signed P-256 certificate, its key and an unrelated key in
`ext/httpstest/certs.h`; test material, never commit it), builds `https-dut.yaml` (ESP32-C3, logs on USB), flashes,
takes the address from the serial log and runs:
- `t1.sh HOST`: one GET with the TLS time, 20 sequential, 6 parallel three times and the 16 KB body. The fixture has
no event source, so the 501 that #22185 sends for an event stream on HTTPS is not covered here.
- `stall.py HOST`: arms a switch to HTTP and to 8443, opens two idle TCP clients (no ClientHello) on 443 before it
runs, then switches back; every switch must be accepted and work, and the idle clients must be closed.
- `t2.sh HOST`: HTTP and back, an armed switch to 8443 with a client open that sends a handshake record header and
never the rest, 60 requests that must all get a 200 for a heap check (compare the `/hw` heap before and after),
then the bad key. The server must log the error and stay off, without falling back to plain HTTP; reset the board
afterwards.
The runner fails on any unexpected status, a missing key error for the bad key, a reset or a task watchdog. `https-soak.yaml` adds a switch between 443
and 8443 every 20 s for a long run with clients attached. Each HTTPS connection takes about 26 KB of internal RAM
(no PSRAM on the C3), so watch the `ALIVE heap=... min=...` lines.
@@ -1,21 +0,0 @@
# matrix_keypad, wiegand, rdm6300 and key_collector without hardware (#21787, #21788, #21790)
All on a D1 mini with no wiring: `scripts/hub_input_sim/hub.yaml` and `sim.hpp`.
- Keypad: one row (GPIO5) and columns GPIO4, 14 and 12 with pull-ups. `sim::press(pin)` switches the column to
`OUTPUT_OPEN_DRAIN` driven low, so the single row reads that key pressed on every scan; `sim::release` goes back
to `INPUT_PULLUP`.
- Wiegand: D0 on GPIO13, D1 on GPIO0. Call `sim::wiegand_arm()` once, then `sim::wiegand(value, bits)` sends the
pulses (80 us low, 1.5 ms apart, most significant bit first). `pinMode(OUTPUT_OPEN_DRAIN)` clears the pull-up and,
with the output latch low, makes a falling edge that adds a bit: write `GPOS` high before the mode switch and set
`GPF |= 1 << GPFPU` after. The interrupt type survives `pinMode`.
- rdm6300 reads UART0 with its loopback bit set (`USC0(0) |= 1 << UCLBE`), so the logger runs with `baud_rate: 0`
and the log goes over the API. Frames are 0x02, 12 ASCII hex characters (version, 4 id bytes, xor) and 0x03. The
uid binary sensor pulses on and off per read.
- key_collector takes both the keypad and wiegand as `source_id`.
- `run.sh LABEL` flashes over serial, reads the API log until `DONE` and writes `out-hubsim<LABEL>.ev`; diff the
`[ev` lines of dev and the PR.
- Wiegand frames with valid parity: 26 bit 0x3579bdf (11259375), 34 bit 0x3bd5b7dde (3735928559), 37 bit
0x1b4b4b4b4a (24253932965). 0x3579bdd fails parity, so only `on_raw` fires for it.
- rc522 and sx1509 need their chips; compile them only.
- Results: https://github.com/esphome/esphome/pull/21790#issuecomment-6491675405
@@ -1,28 +0,0 @@
# hx711 without a chip: fake HX711 on the same ESP32 (#8899)
`scripts/hx711`: classic ESP32, no wiring. SCK is GPIO32, DOUT GPIO33 (configured as an input with pull-up, so DOUT
reads busy until the fake runs). `hxsim.hpp` starts from `on_boot` priority -100 (after the component has set up its
pins), switches both pins to `GPIO_MODE_INPUT_OUTPUT` (it reads the clock and drives the DOUT level the component
reads back) and runs a task pinned to core 0 (the ESPHome loop runs on core 1; core 0's idle task is removed from
the task watchdog).
- Ready means DOUT low; the task waits for the clock with interrupts off in 2 ms windows. Each rising edge puts the
next bit out and the 25th sets DOUT high; extra pulses pick the next conversion (25 A/128, 26 B/32, 27 A/64), and
each conversion takes 100 ms. Clock high for more than 60 us is power down (back to A/128), clock low powers up.
- Values encode the conversion: A/128 is 128000+n, A/64 64000+n, B/32 -(32000+n), so a published value shows which
conversion it came from. `check.py CAP...` matches every `Got value` against the served values and exits non-zero
on an unmatched value, no values or a crash.
- `mode`: 0 normal, 1 DOUT stuck high, 2 DOUT left low after the read.
- The waiting and shifting code must run from IRAM. `IRAM_ATTR` on inline class members either gets inlined into
flash code or fails to link ("dangerous relocation: l32r: literal placed after use"); use static free functions
with `IRAM_ATTR __attribute__((noinline))` and check with `xtensa-esp32-elf-nm` that they sit at 0x4008xxxx. Run
from flash, the first transfer after boot lost one clock pulse (the value shifted right by one bit). Log from the
main loop (an interval drains an event ring), never inside the critical section.
- Runs: `hxbase` (65 s), `hxpr1` channel B plus set_gain and power actions (115 s), `hxpr2`
power_down_after_reading (45 s). `hx-common.yaml` starts each run's `run_all` script and logs the `DONE` line.
`build.sh NAME TREE LABEL` writes `NAME<LABEL>.yaml` with its own name (so dev and the PR builds of the same config
do not share a build directory) and builds it; then `flashcap.sh DIR NAME<LABEL> TREE SECONDS` (`PORT`, `SC` in
the environment), which fails without a `DONE` line and runs `check.py`.
- The configs have no Wi-Fi on purpose: the fake keeps core 0 busy with interrupts off in 2 ms windows, which would
starve the Wi-Fi task. Keep the harness without Wi-Fi, API or OTA.
- Result on #8899: no missed pulses over 141 transfers, and every published value matched.
@@ -1,16 +0,0 @@
# Fake I2C slave (#21586)
`scripts/i2c_slave`: a D1 mini running an Arduino `Wire` slave at 0x40 (`i2cslave.yaml` with `i2cslave.hpp`): a fake
HDC1080 plus a 256 byte register file, and reads of 0x7E and 0x7F stretch the clock for 0.5 and 5 ms. It needs
`libraries: [Wire]` and 160 MHz. With jumper wires only and the internal pull ups it works to about 50 kHz; it cannot
keep up with a true 100 kHz hardware master.
The master (`i2cbk.yaml`, a BK7238 on P26/P24, needs the software I2C bus from that PR) writes a counter, reads it
back with a repeated start, probes an absent address and reads both stretch registers every 2 s, logging `RW OK`
(the read back matches, the absent address NACKs and both stretched reads succeed) or `RW BAD` with running totals.
Control: the same blocks on a classic ESP32 devkit (SDA GPIO21, SCL GPIO22) with hardware I2C at 25 and 50 kHz got
every repeated start read right, so failures on a bit banged master at a similar real clock point at the master.
On the NiceMCU WB3S V1 board (BK7238), P26 and P24 are on the right-hand header.
Fake devices that need no real chip (in-firmware buses, the Pico 2 W target, the DS2482-800 simulator, NACK
injection) are in [fake_i2c.md](fake_i2c.md).
@@ -1,14 +0,0 @@
# i2s_audio
## I2S microphone loopback on one S3 (#22130)
With no I2S microphone at hand, `scripts/i2s_loopback/` makes one. `dcgen.hpp` runs an ESP-IDF std TX channel on
I2S1 as master (GPIO4 BCLK, 5 WS, 6 DOUT, 16-bit stereo) in its own task, switching patterns (DC step, opposite DC
per channel, DC plus a 1 kHz tone, full and half scale 50 Hz squares) through `dcgen::set_mode()`. Jumper 4 to 15,
5 to 16 and 6 to 17 to an `i2s_audio` microphone on I2S0 with `i2s_mode: secondary`. `dcgen::on_data` (registered
with `add_data_callback`) keeps per-segment and last 500 ms stats plus a 1 ms trace of channel 0, and `report()`
logs `SEG` and `SETTLE` lines from an interval. `run.sh LABEL [SAMPLE_RATE] [CHANNEL]` flashes and captures 60 s,
and `sum.py` tabulates. The segment min and max include the tail of the previous pattern (capture latency), so judge
with the tail values. The runner fails on a missing segment, a full-scale square under rms 8000 (no signal through the
jumpers), on either channel for a stereo run, or a crash after the first segment.
Results: https://github.com/esphome/esphome/pull/22130#issuecomment-6615554179
@@ -1,13 +0,0 @@
# ld2412
## Output pin level and the basic configuration command (#21353)
`templates/ld2412-select-only-dut.yaml` (ESP32-S3, the module on GPIO43 and GPIO44 at 115200, only the output pin
level select, the module's OUT pin on GPIO38 as a binary sensor plus the presence sensor) with `uart: debug:
direction: BOTH`. Drive the select with `scripts/ld2450/lddrive.py HOST KEY LOGFILE sel:NAME=OPTION` and read the TX
dump for command `02` carrying the level byte, then the OUT pin binary sensor against presence: with level high the
pin follows presence, with level low it is inverted. A module that never answers the boot query (no `<<<` lines)
only shows the held back path: `Command 02 held back until the module reports its settings`, a query `12`, and after
2 s `Command 02 not sent, the module did not report its settings` with the select republished to the last known
level. With the full set of numbers configured a select change also needs every number to have a state, so wait
for the boot query answer before judging.
@@ -1,21 +0,0 @@
# ld2420 without a module (#21914)
`scripts/ld2420_sim/` runs the hub on a D1 mini UART0 with the loopback bit set and no radar. A `uart: debug` TX hook
(delimiter `04 03 02 01`, the command footer) hands each command frame the hub sends to `ldsim::on_tx()`, which writes
a success ack right behind it: the hub reads its own echo and then the ack. The acks carry the version (the `fw`
substitution), the min and max gate and timeout registers and the gate parameters, so `setup()` completes (`Sim stats`
logs `cmds 21 acks 21`). Template buttons then inject energy frames (`Energy steps`) or simple mode `ON`, `OFF` and
`Range N` lines (`Simple steps`). Firmware v1.5.3 or older keeps the hub in Simple Mode.
- `run.sh LABEL energy|simple HOST` builds, flashes and records two `lddrive.py` runs over the API; `compare.py` takes
the same run of two builds and prints PASS when the state sequences after the steps button match, every setup
command was answered, a Distance and a Presence state arrived and no ERROR line was logged.
- The loopback bit is set at `on_boot` priority 900: after the UART is set up and before the hub's blocking `setup()`.
- `fire_trigger_()` hands the debug lambda the debugger's own buffer, which writing the ack changes; `on_tx()` copies
it first, and ignores its own acks (command high byte 0x01) when the nested call sees them.
- The hub also reads its own echoed command frames. A read register command carries `00 00` where an ack has its error
word, so the echo counts as that command's ack and every real ack lands one command late. The Firmware text sensor
published during `setup()` therefore shows `v0.0.0` in this harness; the config dump and the Simple Mode check see
the simulated version. A real module does not echo, so this harness cannot check that text sensor value.
- Energy mode and simple mode publish at most once a second; a burst of 5 frames 100 ms apart publishes only the first.
- Results: https://github.com/esphome/esphome/pull/21914#issuecomment-6517294344
@@ -1,68 +0,0 @@
# ld2450
## LD2450 polygon zones (#20154)
To make a target "leave" without anyone moving, set the radar's Zone-1 numbers over the target and
switch the zone type to `Filter` (the count drops to 0 within 0.5 s); set it back to `Disabled` after.
Writing those numbers blocks the ld2450 loop about 50 ms.
## Zone numbers round trip (#21146)
`scripts/ld2450/zonedrive.py HOST KEY(- for plaintext) set:NAME=VALUE sel:NAME=OPTION wait:S list` sets numbers and
selects over the API and prints every LD2450 state update. After each set the hub sends the set zone command, queries
the radar and republishes all twelve coordinates from the answer, so set each coordinate of each zone to a distinct
value and check the readbacks; no target is needed. Readbacks can arrive late over Wi-Fi, so match them by content.
Results: https://github.com/esphome/esphome/pull/21146#issuecomment-6278026922
## ESP8266 loopback harness, no radar needed (#21349)
`templates/ld2450-loopback.yaml` (package; substitutions `name` and `baud`) runs the hub on UART0 (GPIO1 and GPIO3)
with `logger: baud_rate: 0` and sets the UART0 loopback bit in `on_boot` (`USC0(0) |= (1 << UCLBE)`), so everything
the hub or a `uart.write` action sends comes back on RX. Template buttons inject periodic frames (all four direction
strings, targets 2 and 3), query zone acks (zone type 0, 1 and 2 for the select readback) and call the name based
setters with a valid and a bogus name. `uart: debug: direction: TX` delimited on the command footer dumps every
command the hub sends. Drive it with `scripts/ld2450/lddrive.py HOST KEY LOGFILE press:NAME sel:NAME=OPTION wait:S`
(logs over the API at VERBOSE, 2 s between steps because the API log stream drops lines while `send_command_`
blocks), then `txsum.py LOGFILE` lists the TX frames per step; diff the summaries of the two builds. The hub reads its
own commands back and logs `Invalid status` for each, which is harmless. The boot readback of the baud rate select
comes from the UART setting, so a second build at `baud: "9600"` checks the flash table lookup.
Results: https://github.com/esphome/esphome/pull/21349#issuecomment-6332320026
## Frame splitter collisions (#21357)
The loopback template also carries the zone 1 numbers and seven collision buttons: a periodic frame with the
command footer inside target 1, zone acks with `55 CC` and with `04 03 02 01` inside the coordinates, a periodic
frame cut after 12 bytes followed by a zone ack, a frame missing its last byte followed by a complete one, a bogus
255 byte length then a frame, and garbage then a frame. Judge by the state updates plus the `Handling Periodic` and
`Handling Ack` lines. Through a real radar the set zone ack is sometimes corrupted by the radar itself (its tail
replaced by the periodic frame it was sending, for example `04 03 03 03 00 ... 55 CC`), so count readbacks over at
least 24 selects per build and read the raw bytes with `uart: debug: direction: RX` (`!extend` the package's uart
id) before blaming the parser; the API log stream drops lines under that dump volume, so some misses stay
unclassified.
Results: https://github.com/esphome/esphome/pull/21357#issuecomment-6333244886
## Frame stream harness: presence hold and link loss (#21733, #21734)
`scripts/ld2450/stream-harness.yaml` is a loopback harness that feeds the hub one periodic frame every 100 ms from a
mode global set by API buttons: no target, target 1 approaching, silent, or 12 garbage bytes per tick (what a radar
at another baud rate looks like). `has_target` has `filters: []` so the hub's own hold is what gets timed, and every
change logs `presence raw ON|OFF at <millis>`. Add `stream-connected.yaml` as a second package on builds whose ld2450
has the link watchdog (`connected` binary sensor).
- `holddrive.py HOST OUT`: for `presence_timeout` 5 and 0, three seconds of target frames, then empty frames; prints
the ms from the press to the off line, then sets 0 and 20 and reads the number back after a restart. On dev 0
still held 5 s and snapped back to 5; with #21733 it clears on the next empty frame (under 200 ms) and stays 0.
- `linkdrive.py HOST OUT`: steps through target frames, 10 s of silence, empty frames, 10 s of garbage, target
frames, then the hub's radar restart followed by 3.5 s and by 15 s of silence; prints every state change and link
log line with its time. Dev freezes every entity through silence and garbage. Run against a real radar too: a
radar restart and a Bluetooth toggle must not report a loss (the Apollo R PRO-1 ETH did not).
- A freshly booted ESP8266 delays API commands sent in its first seconds and then runs them back to back; the
drivers wait 8 s after connecting before timed presses.
## BT MAC sensors (#21731)
`scripts/ld2450/macdrive.py HOST OUT` reads every LD24xx BT MAC, Bluetooth and firmware entity, turns each Bluetooth
switch off, then on, and prints the values after each step. The MAC sensors are often `disabled_by_default` in
vendor configs but still publish over the API. On the Apollo R PRO-1 ETH both radars (LD2450 fw 2.04, LD2412 fw
1.26) have the multicast bit set in the first MAC byte, which dev showed as `unknown`. A radar MAC identifies a
device: quote only its first byte in PR text.
@@ -1,29 +0,0 @@
# Bit-banged LED drivers without the chips (#21841 to #21847)
The GPIO LED drivers (bp5758d, bp1658cj, sm2235, sm2335, tlc5971, tlc5947, my9231, sm16716) never read the chip
back, so a classic ESP32 devkit can capture its own pads with no wiring. `scripts/led_driver_sniff`.
- `sniff.hpp`: SPI2 and SPI3 run as DMA slaves fed from the driver's clock and data pads through the GPIO matrix
(`esp_rom_gpio_connect_in_signal`, pad input enabled with `gpio_input_enable`). Mode 1 samples on the rising edge
of its clock input (measured, not what the mode table suggests): SPI2 takes the clock straight (rising-edge bits,
`R` lines) and SPI3 inverted (falling-edge bits, `F` lines; my9231 clocks a bit on both edges). CS is GPIO2,
driven by the test. PCNT counts clock and data edges and latch rises per window.
- ESP32 slave DMA drops a partial last word, so `close()` pads the clock with whole pulses to a 32-bit boundary plus
32, and the bit count comes from PCNT. `selftest()` sends a known 57-bit pattern with the clock idling low and
high; `selftest.py` checks it, and `run.sh` runs it on every capture.
- bp5758d, bp1658cj and sm10bit_base (sm2235, sm2335) release the data line for the ack with `pin_mode(INPUT)`, and
`pin_mode(OUTPUT)` disables the pad input. The `sniff` local component (`ext/`) links with
`-Wl,--wrap=gpio_set_direction` and the header re-enables input on the sniffed pins. The ack bit reads the
floating line, the same on every build.
- `gen.py` writes `led.yaml`: all eight drivers on separate pins (bp5758d 25/26, bp1658cj 23/4, sm2235 18/19, sm2335
21/22, tlc5971 27/32, tlc5947 33/13 latch 14, my9231 16/17, sm16716 5/12, selftest 15/0) and a script per driver:
one window per step (open, set levels, 200 ms of main loop, close), a repeated step that must send nothing, two
direct `loop()` calls timed with `esp_timer`, and an idle window.
- `run.sh LABEL` builds, flashes, captures until `DONE` and checks the selftest. `compare.py BASE PR DRIVER` diffs
every window of one driver between two runs and decodes it (9-bit groups for the BP and SM frames, 12-bit words
for tlc5947, 16-bit for tlc5971, the two-edge interleave for my9231, 50 zero bits plus 25-bit groups for
sm16716). Loop timing varies about 3 % between builds even for drivers a PR does not touch.
- my9231 toggles DCKI with `!digital_read()`. ESP32 output pins have the pad input disabled, so without the
sniffer's input enable the read is always 0 and the clock never toggles (on dev too).
- Out-of-range channels: run `esphome config` with channel = last and last + 1 on dev and the PR.
- Results: https://github.com/esphome/esphome/pull/21844#issuecomment-6491228132
@@ -1,63 +0,0 @@
# Addressable LED strips (#21447, #21445)
- To exercise a failed strip allocation, use a classic ESP32 without PSRAM with `num_leds: 65535` and
`channel_colors: GRBW` (262 kB, bigger than any internal block). `num_leds` is uint16 in the drivers, larger
values wrap. On dev such a strip boot-loops the board.
- Never force allocation failures by hogging RAM instead: Wi-Fi then aborts in `operator new` or the loop task
trips the task watchdog.
- On the ESP32-S3 give each RMT strip `rmt_symbols: 48`, or the first channel takes all 192 symbols.
- A board with a few WS2812 on a pin already defined as a light can be extended with `id: !extend <light id>` to
add effects; restore its own config afterwards.
- Loop cost of a strip (#19337): give each strip an `addressable_lambda` effect with `update_interval: 0ms` that
changes every pixel, and add `runtime_stats: log_interval: 30s`; compare the main loop and light times per pass,
leaving out the first period after boot. The strips need no LEDs attached. A classic ESP32 has 512 RMT symbols in
all, so three strips need `rmt_symbols: 128` each.
## RMT channel and memory budget (#22172)
`scripts/rmt_budget/`: each line of `cases.txt` is a mix of strips, transmitters and receivers with their
`rmt_symbols` (`s:96`, `t:def`, `r:48`, ...) on an ESP32-S3 or ESP32-C6, and `gen_case.py CASE` turns it into a
config whose strips have an `output_id` and which logs `STATUS so0=<is_failed> tx1=...` every 3 s. `run.sh CASE...`
builds each case under one name per board (so builds stay incremental), flashes, captures 15 s and prints the STATUS
line and the RMT driver errors; it exits 1 when a case printed no STATUS. `verdict.sh CASE...` runs only
`--only-generate` and prints the config errors, the RMT memory warnings and the components registered, to compare
with what the board then does. No LEDs are needed: allocation failures show at boot.
- On the S3 USB console the ESP-IDF `no free tx channels` lines are printed before the port reopens; the C6 on
UART0 shows them.
- S3 TX channels can use RX memory (384 symbols at most) but only start on blocks 0 to 3, so two 192 symbol strips
do not fit.
- 17 of 17 predictions of the PR matched the driver. Results:
https://github.com/esphome/esphome/pull/22172#issuecomment-6615083139
## Capture the wire, not the buffer (#21577)
`templates/led_wire/wire.hpp` reads what the strips send, with no wiring:
- RMT RX channels on the `esp32_rmt_led_strip` pads at 10 MHz, decoded with a high-time threshold per chipset
(ws2812 0.4/0.8 µs: threshold 7 ticks; sk6812 0.3/0.6 µs: threshold 4);
- an SPI2 DMA slave fed from the `spi_led_strip` pads, with `spi: interface: spi3` for the strip.
`led-wire-dut.yaml` (classic ESP32) drives a GRB ws2812 strip, a GRBW sk6812 strip, an SPI strip, an RGB light and a
partition through steps S0 to S8 (on, `addressable_set`, lambda writes, partition, effect, power limit, off), logging
the decoded `RMT`, `SPI` and buffer `GET` lines and `DONE` per step, then runs `stress_step()` over 300 shows and
logs bad frames per strip. Diff the step lines of dev and the PR.
- A comparison of the buffers alone missed a PR bug in which the start frame was not sent.
- Give the captured strip `rmt_symbols` that hold a whole frame (192) and capture one RX channel at a time: with 64
symbols the TX refill interrupt stretches bits on dev and the PR alike while the capture runs. The substitutions
at the top of the config pick the strip.
## rp2040_pio_led_strip: a self-sampling PIO probe (Pico 2 W)
`scripts/pio_probe/pioscope.hpp` samples any GPIO from PIO2 at 25 MHz while another peripheral drives it (PIO reads
the pad without taking the pin) and decodes WS2812-style pulses into bit timings and bytes; no wires or LEDs.
`pa.yaml` probes five strips on PIO0 and PIO1 (WS2812 and two custom timings), `pc.yaml` one strip after claiming
DMA channels 0 to 11. `run.sh pa|pc LABEL` builds, flashes, captures 40 s and prints the `RESULT` lines; a correct
frame of two LEDs set to `Color(0xA5, 0x3C, 0x0F)` reads `3ca50f3ca50f`.
- Turn the light on at full brightness before probing, or color correction writes zeros.
- The probe FIFO overruns once in a while: count only full captures. `run.sh` fails unless every strip gave at least
one correct frame.
- An RP2350 `panic()` escalates to a HardFault and the rp2 crash handler reboots within about a second, so a panic
during component setup boot-loops before USB CDC enumerates and the board looks dead (no port, no BOOTSEL drive).
Hold BOOTSEL while plugging it in and flash the UF2 drive. To see such a fault, trigger it after boot.
@@ -1,162 +0,0 @@
# libretiny
## LibreTiny rtc preference emulation (#21007)
The PR keeps `storage: rtc` preferences in FlashDB and deletes them on the first load or save after a boot
whose `lt_get_reboot_reason()` is not software, watchdog, crash or sleep. Only the families listed in
`_libretiny_rtc_supported()` accept the config keys; on others force the backend in with
`platformio_options: build_flags: ["-DUSE_LIBRETINY_RTC_PREFERENCES"]` after confirming the rejection.
- Harness: `scripts/libretiny_prefs/ltprefs.hpp` plus `templates/bk72xx-rtc-prefs-dut.yaml`. `ltprefs_boot()`
loads one rtc and one flash preference, a second pair that shares one key as rtc and as flash, and a third
rtc entry (so a hard reset drops three entries in one pass), logs the reason and both results, saves `100 + step`, syncs; after
a templated delay `ltprefs_exit()` bumps the flash-backed step and runs the step's action (`lt_reboot()`,
`__builtin_trap()`, `lt_reboot_wdt()` or idle). The last 8 boot reports are kept in a flash preference and
repeated in the 10 s alive line, so a boot missed by the capture (a power cut, an OTA-only board) is still
readable. Bump `run:` for fresh keys.
- A store to an unmapped address does not fault on the ARM968, the board carries on: use `__builtin_trap()`
for the crash row. The SDK crash handler reboots about 10 s later. Works on BK7238 and BK7231N.
- Hard resets: `serial_capture.py ... --reset` pulses RTS on CEN (reported as Power-On). A real power cut
needs a hand or a smart plug; the history in the alive line covers the boot the host cannot see. On the
Beken SDK a chip-enable reset and a power cut both report Power-On, there is no separate reset-pin source.
- Step 0 and step 8 wait 30 s before acting so the host can open the port (and pulse a reset) after a flash
without losing the first boot; the flash tool's own reset starts the sequence immediately otherwise.
- OTA-only board: keep the device's wifi, api and ota blocks verbatim, keep safe_mode, read logs with
`esphome logs <yaml> --device <name>.local` (the API attaches late, hence the history), and restore the
device's own config afterwards.
- Plain-build comparison: `raw_firmware.bin` differs by the timestamp and by `__LINE__` in log calls of
functions below the added code; map offsets through `objdump -h` load addresses and `addr2line` before
calling a byte difference a code change.
## BK72xx crash report on the next boot (#21012)
Harness: `scripts/libretiny_crash/bkprobe.hpp` plus `templates/bk72xx-crash-probe-dut.yaml`. A flash
preference holds the step; `on_boot` (priority -100) logs the reset reason, the SDK start type, two canaries
and hex dumps of the low SRAM, a set of marker words and the record area after `.bss`, waits 30 s on step 0
(so a capture can be opened after the flash) or 5 s, saves `step + 1`, syncs, then acts: 0 `__builtin_trap()`,
1 call into unmapped memory, 2 unmapped and unaligned reads and a store (no fault on the ARM968), 3
`lt_reboot()`. A `globals: restore_value` step counter does not work here: it is only saved from the global's
loop, which a crash 50 ms later never reaches; save an `ESPPreferenceObject` and `global_preferences->sync()`
first. Bump `run:` for fresh keys. Keep the `wifi:` block: the bug the fix addresses only shows with Wi-Fi up.
Flow: `flash_bk72xx.py` (retry up to three times), one `serial_capture.py ... --reset` capture of 150 to 230 s,
then `grep -a "libretiny.crash\|probe"`. Decode with
`arm-none-eabi-addr2line -pfiaC -e .pioenvs/<name>/raw_firmware.elf <addr...>` (the ELF is `raw_firmware.elf`
on LibreTiny), or run `scripts/libretiny_crash/decode_capture.py <yaml> <capture>` from the config directory
to feed the capture through the CLI's `LogLineProcessor`.
Expected: `*** CRASH DETECTED ON PREVIOUS BOOT ***`, `Reason: Undefined instruction`, PC on the `udf`,
LR = PC + 1, BT0..BT7 walking the lambda, `StatelessLambdaAction`, `Action::play_complex`, `DelayAction`,
`Scheduler::call`, `Application::loop`. The wild call reports where the core ended up (it executes zeros as
Thumb NOPs until it wraps into real code), not the called address. Without the fix a dev build with Wi-Fi
connected never comes back from the crash; see the BK72xx section in `boards.md`.
OTA-only board: copy the device's own config, add the probe include and the step machine (step 0 crashes
45 s after boot, later steps idle), keep its wifi, api, ota and safe_mode blocks and use the secrets file
next to that config. A LibreTiny OTA is a 1.5 MB UF2 and takes minutes on a slow link, so do not wrap the
upload in a short timeout. Read the replayed report with `esphome logs ... --device <name>.local` (an API
client gets it on subscribe) or on the board's serial log port if it has one.
## RTL8720C crash report on the next boot (#21648)
`templates/rtl8720c-crash-buttons-dut.yaml` has one API button per case: `trap` (`__builtin_trap()`, usage fault),
`bus fault` (store to 0x70000000, imprecise, CFSR 0x400), `wild call` (call to 0xFFFFFFF1, MemManage fault with PC
0xFFFFFFF0 and LR in the caller), `isr trap` (a trap from a spare interrupt pended by software, hard fault), `hang`
(interrupts off, the watchdog resets it and nothing must be reported) and `restart`. Every boot logs
`boot reason N, crash record yes|no|n/a`; `n/a` means the handler is not built, as on a dev control build.
Flow per build: flash with `flash_rtl87xx_kit.py`, start one `serial_capture.py PORT 600 OUT --released --ms`, then
`scripts/libretiny_crash/rtl_drive.py HOST OUTDIR TREE YAML trap restart "bus fault" "wild call" "isr trap" hang restart`.
The `restart` after the first crash checks the report shows only once. Time each reset from the serial capture
(the ROM fault dump to the next `ROM Version` line), not from the API port: the board is back before an API client
notices it went away. Compare the reported PC with the `PC =` line of the ROM dump, and check the decoded lines in the
`caseN-*.txt` files. Pass the UF2 by name (`firmware.uf2`): the build directory holds a second identically sized copy.
Regression rerun of the same flow (#21728): `scripts/libretiny_crash/rtl_rom_vs_report.py CAPTURE` lists, for each ROM
fault dump in a `--ms` capture, the ROM's CFSR and PC, the ms to the next `ROM Version` banner and the Reason, CFSR, PC
and SP the next boot reported, so two builds compare line by line. The ROM lines start with a bare CR; split the
capture on newlines only. The imprecise bus fault's PC moves between builds (it is wherever the core was when the
fault was raised); compare it with that run's ROM dump, not with another build. SP stays the same per fault (8 word
frame, no FPU). On the BK7238 time the reboot from the button press to the next `BK7238_1.0.14` banner (0.6 to 0.7 s).
## BK7238 BLE and flash sector safety (#21735)
The Beken BLE bond store reads its partition at boot and erases that sector when the CRC does not match; before
LibreTiny 1.14 the partition was unmapped and pointed at sector 0, erasing the bootloader (#18646). To prove a change
like this safe on a board that cannot be recovered without a dump:
1. Take a full backup first: `scripts/bk72xx_flash/readback.sh full-before` (ltchiptool family `beken-7238`, about
190 s for 2 MB). Keep it until the board is back on a known build.
2. Serial flash a build without the feature, then deliver the feature build by OTA (the path users take). Use
`bk72xx: framework: sdk_silent: none` with `logger: hardware_uart: UART1`, so the SDK's own lines (bootloader
banner, `CRC fail, remove bonded info`) show up in the capture.
3. Soak with Wi-Fi up, OTA again from the new build, pulse CEN a few times (`serial_capture.py --reset`), and check
each boot comes back through the bootloader.
4. Read the whole chip again and run `scripts/bk72xx_flash/partdiff.py full-before.bin full-after.bin
<libretiny>/boards/_base/beken-72xx.json`: bootloader, calibration and userdata must be unchanged; app, download
and one KVS sector change normally.
Check what already sits in the target partition before the first boot: on an XH-WB3S that shipped with Tuya firmware,
0x1E1000 (the `ble_bonding` partition of the generic Beken layout) held the Tuya `diff2ya` record (magic `ba dc cd
ab`), which the bond store erased on its first boot. Nothing depended on it there, but say so in the results.
## BK7238 OTA and the board layout (issue #18222)
A BK7238 has one of two bootloaders, and the board in the YAML must match it: Beken OEM (`BK7238_1.0.14` in the
boot banner, `generic-bk7238`, OTA as RBL to `download` at 0x132000) or Tuya T1 2.0.0 (`generic-bk7238-tuya`,
`t1-*`, `download` at 0x12C000 plus a `diff2ya` record at 0x1E1000). `ltchiptool uf2 info` on `firmware.uf2` shows
the layout an image targets (`FAL_PTABLE`, `OTA_PART_INFO`). Measured on the OEM bootloader (2026-10-27):
| Running | Uploaded | Result |
|---|---|---|
| Tuya layout | Tuya layout | upload succeeds, bootloader prints `App verify failed! Need to recovery factory firmware.`, old build stays |
| Tuya layout | OEM layout | applied |
| OEM layout | Tuya layout | `End error: 9` (`UPDATE_ERROR_ACTIVATE`: no `RBL` at the running download offset), old build stays |
| OEM layout | OEM layout | applied |
Run it with a full backup first (`scripts/bk72xx_flash/readback.sh`), `sdk_silent: none` so the bootloader's lines
show, and each result checked against `build_info.json` over the API. A Tuya-layout build on an OEM-layout module
reads the RF calibration from 0x1E3000: copy the 0x1E0000 sector there for the test and erase it afterwards. The
Tuya OTA writes up to about 0x1EF000 and its own settings at 0x1E4000, so write those sectors back from the backup
and check with `partdiff.py`.
## RTL8710B Wi-Fi join diagnosis (issue #21742)
For a board that joins rarely: build `dev` with `sdk_silent: none`, log `wifi_get_last_error()` and
`rtw_join_status` after each failed `WiFi.begin()`, and dump the efuse map once (see the AmebaZ section in
`boards.md`). The driver log tells the stages apart: `start auth to` with nothing after it is the AP not answering,
`auth success, start assoc` then `association success` then error 3 is a failed 4-way handshake, and
`sta recv deauth reason code(6)` is the AP dropping the session mid-handshake. Tally per BSSID: if the share of
auth frames answered falls with distance while receive stays strong, the board's transmit path is weak.
A/B a value one boot at a time so time of day and AP state hit both sides equally. Keep the trial counter in a
`restore_value` global, set the value in an `on_boot` lambda at priority 600 (before Wi-Fi starts), and reboot
after a fixed window:
```yaml
esphome:
on_boot:
priority: 600
then:
- lambda: |-
// value under test, read by the code being measured
wifi::diag_value = (id(trial_idx) % 2) ? 0x3A : 0;
ESP_LOGW("trial", "TRIAL %d start value=0x%02X", id(trial_idx), wifi::diag_value);
- delay: 75s
- lambda: |-
bool ok = wifi::global_wifi_component->is_connected();
ESP_LOGW("trial", "TRIAL %d value=0x%02X result=%s", id(trial_idx), wifi::diag_value,
ok ? "JOINED" : "FAILED");
id(trial_idx)++;
App.safe_reboot();
```
Turn off `api:` and `wifi:` `reboot_timeout`, and leave out `ap:` unless the AP is the variable under test.
Do not cycle trials with `wifi.disable` and `wifi.enable`: doing that while connected reset the RTL8710B on the next
scan. Results from 2026-10-27, on one BW12 with blank efuse calibration: crystal trim `0x20`, `0x30` and `0x38`
all joined 20 of 20 trials, and boosted TX power indexes changed nothing against an AP that answered 0 of 43
auth frames.
Known LibreTiny behaviour seen here: after a join with a BSSID and channel, LibreTiny's partial-scan reset leaves
the next SSID-only join with nothing to scan (`RTW_NONE_NETWORK` in about 18 ms). That is a firmware bug, not
the board; passing channel 0 avoids it.
@@ -1,36 +0,0 @@
# GPIO wakeup from auto light sleep (#21074)
`scripts/light_sleep_wake` needs no wiring. LEDC on `LEDC_USE_RC_FAST_CLK` with
`sleep_mode = LEDC_SLEEP_MODE_KEEP_ALIVE` keeps toggling GPIO10 at 2 Hz through light sleep, and an
`ESP32InternalGPIOPin` interrupt (`ANY_EDGE`) on the same pad timestamps every edge in an IRAM handler.
`wakeprobe::report()` logs every 30 s: edges seen and expected, the shortest and longest gap, how many edges came
more than 20 ms off the half period, and the SLEEP share from `esp_pm_dump_locks()` (needs `profiling: true`).
- Native ESP-IDF builds need `include_builtin_idf_components: [esp_driver_ledc]`.
- After `ledc_channel_config` call `gpio_input_enable(pin)`, never `gpio_set_direction(INPUT_OUTPUT)`: that routes the
pad back to a plain GPIO output, the wave stops and the pad reads a constant 1.
- The C3 shares one LEDC clock across timers, so a board whose own config drives LEDs through `ledc` needs a test
config without them. Logging over the API works with `logger: baud_rate: 0`.
- Read the reports over the API with `esphome logs ... --device <ip>` under `timeout`. Run PR, dev, then the PR
again. On a C3 bulb dev caught every edge but handled 8 of 845 more than 20 ms late
(up to 45 ms), the PR none; both slept 57 to 58% of the time.
## Peripheral power-down needs an external signal (ESP32-P4)
LEDC in `LEDC_SLEEP_MODE_KEEP_ALIVE` keeps the TOP power domain on, so the self-generated wave above never tests
`power_down_peripherals`. With that option the PR's ext1 path also hands an LP pin to the LP IO block, and an LEDC
wave on the same pad no longer reaches the input (the pad reads 0).
- `wake-stim.yaml` puts a 2 Hz square wave on GPIO25 of a classic ESP32 (LEDC on REF_TICK). Wire it to GPIO4 of the
board under test; boards on the same USB host share ground.
- `wake_detail.hpp` with `wake-detail-esp32p4.yaml` (substitution `power_down`): GPIO4 is the any-edge interrupt pin
and GPIO22, jumpered to it, is read as the true level. The first 40 s hold a `NO_LIGHT_SLEEP` lock, then sleep is
allowed. Each report counts interrupt calls, real edges (the GPIO22 level changed) and calls with no change, per
phase, and two windows (from 9.5 s and from 69.5 s) log every call with its gap and both levels. A light-sleep
exit callback counts wakes when `CONFIG_PM_LIGHT_SLEEP_CALLBACKS` is set.
- Waveshare ESP32-P4-WIFI6 (pre-rev3 silicon, CH343 console): `engineering_sample: true`, `flash_size: 32MB` and
`logger: hardware_uart: UART0`, or the app logs nothing on that port. No Wi-Fi needed. GPIO4 is the left header,
12th pin from the USB end; GPIO22 the right header, 9th.
- Result on #21074 at 2ef417bd81 with peripherals powered down: the PR caught all 644 real edges (dev 66) but added
4642 calls while the line was high, one per sleep cycle (about 16 ms), with the level read correctly. Peripherals
on: both builds caught every edge. https://github.com/esphome/esphome/pull/21074#issuecomment-6503939850
@@ -1,31 +0,0 @@
# Manual IP and web handler flows (#21708, #21709, #21711, #21712)
## Station manual IP (`scripts/manual_ip/run-sta.sh`)
Set `static_ip` to the board's own DHCP lease so nothing collides, and DNS2 to a server DHCP does not hand out
(9.9.9.9), so the dump and `dns_getserver()` prove the manual values are in use. A missing SSID with its own
`manual_ip` comes first, so the real network is a later table row and inherits the top level `manual_ip`. The probe
logs both DNS servers and resolves a name every 20 s; `ipaddr_ntoa` uses one static buffer, so it uses
`ipaddr_ntoa_r` to log two addresses in one line. PASS needs the address, both DNS servers, a lookup and a ping.
## AP manual IP (`scripts/manual_ip/run-ap.sh`)
The DUT has only a missing SSID, `ap_timeout: 10s` and `captive_portal:`, so its AP comes up on 10.42.7.1; the other
board joins as a client and fetches `http://10.42.7.1/` every 10 s. A D1 mini AP drops some client requests on dev
too, so compare failure counts with a dev run and do not expect zero.
## Ethernet manual IP
Same idea on an Ethernet board: its lease as `manual_ip` plus an outside DNS2 and the DNS probe from
`scripts/manual_ip/dnsprobe.hpp`; restart it over the API and check again.
## Web handlers (`scripts/web_handlers/run.sh`)
`webbase.yaml` adds a GET /probe handler from `on_boot` at priority -100 (the shape of an external component adding
a handler late) and takes a variant: `ws` (web_server), `cp` (captive_portal only, started on the station network by
a button calling `global_captive_portal->start()`) or `prom` (captive_portal and prometheus). The runner fetches
/probe and /, then uploads the same image through web OTA (`curl -F update=@<bin> http://ip/update`; ESP-IDF
`build/<name>.bin`, not `firmware.ota.bin`; ESP8266 `.pioenvs/<name>/firmware.bin`) and checks over the API that the
board is back on that build. On dev too, prometheus GET / gets no answer on ESP32 and 404 on ESP8266.
A background `(cd dir && cmd) &` does not change the parent shell's directory: give capture scripts absolute paths.
@@ -1,18 +0,0 @@
# mDNS responder (#22267)
`scripts/mdns/mdns-common.yaml` (a package) adds a `_hwtest._tcp` service with a short and a 62 character TXT
value and logs free, minimum and largest free heap every 10 s; `mdns-wifi.yaml` adds Wi-Fi from `secrets.yaml` and
switches it off and on every 120 s so the responder restarts. The host's multicast often does not reach the boards
(a host with several network interfaces, or a mesh Wi-Fi network), so the scripts send legacy unicast queries (source port not 5353)
straight to the device's port 5353 with python-zeroconf packets:
- `mq.py IP HOSTNAME dump` asks for the `_esphomelib` and `_hwtest` PTR records, the A record and the SRV and TXT
records of both services, prints the answers and exits 1 when one is missing. Diff the dump between builds.
- `mq.py IP HOSTNAME hammer N [TIMEOUT]` sends N questions back to back (0.5 s timeout each) and counts misses per
question. It exits 1 when nothing was answered, or when more than `MAX_MISS_PCT` percent (env) were missed.
- `mq.py IP HOSTNAME lat N` sends A queries 300 ms apart and prints the median, p90, p99 and maximum latency and how
many answers came after 1.5 s or never.
Judge responder timing on an Ethernet board: on a crowded Wi-Fi network back-to-back query loss swung between 0 and
14% between builds for no code reason. Run the hammer across a Wi-Fi off and on cycle too, and compare the heap
lines before and after many cycles.
@@ -1,26 +0,0 @@
# microphone_http_stream (#21593)
`microphone_http_stream` serves raw microphone PCM at `/audio/microphones/<stream_id>` (and a listing at
`/audio/microphones`) on the web server. `templates/microphone_http_stream/`:
- `mh-base.yaml`: Waveshare ESP32-S3-ETH on PoE (logs over the API on Ethernet, the native USB port is the USB host
port), encrypted API, `web_server` on 80 with a dummy sensor and switch, mic start and stop buttons and a line
every 5 s with the mic state and internal and PSRAM heap. Any ESP32-S3 with PSRAM works for `mh-fake.yaml`.
- `mh-fake.yaml`: the stream fed by `ext/fakemic`, a test microphone that publishes 32 ms chunks of a 16-bit counter
(one count per sample) from its own task, so a reader can check every sample. Its "Mic stall" button stops the
chunks for 6 s.
- `mh-usb.yaml`: the stream fed by a USB microphone on `usb_audio` (48 kHz, 16-bit stereo, channel 0 streamed).
Copy the directory next to a `secrets.yaml` with `api_key`, flash, then run
`mhclient.py HOST STREAM_ID [--clients N] [--seconds S] [--pattern] [--stall K] [--stagger S] [--expect-reject R]`.
Each reader prints its HTTP status, format headers, sample count and rate, the longest gap between reads and, with
`--pattern`, every break in the counter. `--stall K` makes reader K stop reading after 2 s while keeping its socket
open, then checks that the device closed it. `--expect-reject R` marks the last R readers as past `max_clients`;
they must get a non-200 status or a close or reset before any samples, and a timeout or a served reader fails.
The script exits 1 when the listing is not a 200 naming the stream, the stalled reader was not dropped, a reader past
the limit was not refused, or any other reader got no 200, no samples, an early EOF, a read error or a broken counter.
Cases worth running on each head: one reader with `--pattern` (rate must match the sample rate, 0 breaks), the
`max_clients` limit plus one with `--expect-reject 1` (note what the extra one gets; the others must be unaffected), a stalled reader among
three (the device should drop the stalled one only), the "Mic stall" button during a read (a gap of about 6 s, then
the counter continues), mic start and stop while readers are attached, and the heap line after many connect and
disconnect cycles. On the USB microphone, check the rate and `rms` instead of the pattern with `--rate 16000 --min-rms 1`, and add `--max-gap-ms` to fail on long gaps; these set the exit code.
@@ -1,18 +0,0 @@
# modem
## PPPoS modem component with no modem attached (#6721)
A boot check on a classic ESP32 devkit with the modem UART pins left open. `templates/modem/modem-common.yaml` is
the package (`api:`, debug `loop_time` and `free` sensors, uptime, buttons for `modem.enable`, `modem.disable` and
`modem.send_at`, a 20 s alive log); `modemo.yaml` is the modem only build with `reboot_timeout: 2min` and the
component test config's `on_boot` block at `priority: -100` (earlier, `modem.send_at` runs before the modem's
`setup()` and logs `Modem DCE not ready`); `modemw.yaml` adds `wifi:` with `reboot_timeout: 0s` so the API stays
reachable. Expect `Modem not responding at 115200 baud` once per pass with each pass blocking the loop about 1 s,
the reboot at the configured timeout (`SW_CPU_RESET`), and a `modem.disable` with no modem answering to block
the loop about 37 s (`Failed to leave data mode`, then the radio off timeout) without tripping the 30 s watchdog
floor because the component feeds it in between. Drive the Wi-Fi build with
`scripts/modem/mdrive.py HOST LOGFILE list press:NAME wait:S` (plaintext API; prints sensor and text sensor
states, saves the device log). Before 8cc8df4a1f a modem only config with `api:` failed validation because a
config dependent `AUTO_LOAD` added `network` after the dependency check; an explicit `network:` block was the
workaround. Results: https://github.com/esphome/esphome/pull/6721#issuecomment-6347395159 and
https://github.com/esphome/esphome/pull/6721#issuecomment-6348520416
@@ -1,141 +0,0 @@
# mqtt
## MQTT (#20433, #17935, #20762, #20767, #20768)
A local mosquitto with `allow_anonymous true`, `log_type all` and `log_dest file`: the broker log gives
each subscription's QoS, the device address (`New client connected from <ip> as <name>-<mac>`) and exact
subscribe counts. Kill and restart mosquitto to exercise `on_disconnect` (reason 0) and resubscription.
Keep `reboot_timeout: 0s` on `api:` and `mqtt:`. The ESP-IDF outbox swings free heap about 2 kB right
after bulk subscribe and unsubscribe; read the heap seconds later over several rounds before calling a
leak. Spawned subscriptions need about 2.5 s to reach the broker before the next publish.
`esphome logs --device MQTT` only uses the MQTT transport when the config has no `api:`. Driver pattern: a
paho script publishes and polls the serial capture file.
## WebSocket transports on ESP-IDF (#16056)
One build per transport from `templates/mqtt-transport-dut.yaml`, with `scripts/mqtt/mosquitto-ws.conf` as the
local broker (mosquitto 2.x from brew has `websockets` support; `log_type all` prints `New connection from <ip>:<port>
on port <listener>`, which proves which listener each client used) and `scripts/mqtt/make_test_ca.sh BROKER_IP` for
the TLS listener's certificate, both run in the scratch directory so keys, logs and outputs stay out of the checkout. `scripts/mqtt/cases.sh NAME KEY BROKER_HOST SUB_PORT CAPTURE [DEV_HOST] [restart]` subscribes
to `NAME/#`, sends a switch command and an `on_message` topic, presses the 3000 byte publish button over the API,
restarts the local broker when the last argument is `restart` (the PID in `mosquitto.pid`, written when the broker
was started with `mosquitto -c mosquitto-ws.conf & echo $! > mosquitto.pid` in the working directory next to the
certificates), checks every listener in the broker config answers again, and prints the broker's message counts with the device log. `mosquitto_sub` cannot speak
WebSocket, so it subscribes on the plain listener of the same broker. Cases: `tcp` on 1883, `ws` on 9001, `wss` on
9002 with `certificate_authority` (the certificate names an address, so `skip_cert_cn_check: true`), `wss` to
test.mosquitto.org on 8081 with no CA for the certificate bundle, and two negatives that must never connect: a
different CA (`mbedtls_ssl_handshake returned -0x2700`) and the self-signed server through the bundle
(`esp-x509-crt-bundle: Failed to verify certificate`, `-0x3000`). `CONFIG_MQTT_TRANSPORT_WEBSOCKET` is on by
default in the generated sdkconfig. The TLS session costs about 29 kB of internal heap while connected; the public
broker carries other devices' `esphome/discover` traffic, which is noise. Results:
https://github.com/esphome/esphome/pull/16056#issuecomment-6301034019
## TLS trust sources on ESP-IDF (#14318)
One build per trust source from `templates/mqtt-tls-dut.yaml`: broker only (port must resolve to 1883),
`certificate_authority` with no port (must resolve to 8883), `verify_ssl: false` with no CA, the CA plus
`client_certificate` and `client_certificate_key` on the 8884 listener that requires one, `transport: wss` with the CA,
`tls: true` to test.mosquitto.org on 8886 for the certificate bundle, and `tls: true` to the local self-signed broker as
the negative. `scripts/mqtt/mosquitto-ws.conf` now has the 8883 and 8884 listeners and `scripts/mqtt/make_test_ca.sh`
also writes `client.crt`/`client.key`. Before flashing, check each build's `src/esphome/core/defines.h` for
`USE_MQTT_TLS`, `USE_MQTT_CERT_BUNDLE` and `USE_MQTT_TLS_INSECURE` and its `sdkconfig.<name>` for
`CONFIG_MBEDTLS_CERTIFICATE_BUNDLE` and `CONFIG_ESP_TLS_INSECURE`: only the bundle builds may carry the bundle and only
the unverified build the insecure flags. `scripts/mqtt/flash_and_drive.sh TREE YAML PORT KEY BROKER_HOST
local|public|neg` runs one build end to end (flash, bounded capture, `cases.sh` with a restart for the local broker,
counts and the broker's per-listener connection lines) and prints the config dump's `TLS:` line (`CA certificate`,
`certificate bundle` or `no verification`). The CLI side (`esphome/mqtt.py`) is covered without a board by
`scripts/mqtt/cli_tls_check.sh TREE [neg] YAML...`, which runs `esphome clean-mqtt` under a timeout: status 124
after `Connected to MQTT broker!` is a pass, and with `neg` each config must instead fail with
`CERTIFICATE_VERIFY_FAILED` and never connect. Python's default SSL
context rejects a CA that lacks a `keyUsage` extension (`CA cert does not include key usage extension`) while mbedTLS
on the device accepts it, which is why the test CA carries `basicConstraints` and `keyUsage`. A broker kill shows as one
`Last esp-tls error: 0x8008` on every build, TLS or not. Results:
https://github.com/esphome/esphome/pull/14318#issuecomment-6311863827
## MAC suffix topics (#9315)
`scripts/mqtt/mac_suffix/run.sh X BUILD` compiles (from `TREE`) and flashes variant X (a defaults, b custom `topic_prefix`, c explicit topics,
d no suffix) of BUILD (`pr` or `base`) on an ESP32 and a D1 mini, records the broker with
`mosquitto_sub -F '@H:@M:@S r=%r %t %p'`, presses Restart through the `cmd_t` found in the discovery payloads, then
holds both chips in the bootloader for 40 s (`esptool --after no-reset chip-id`) so the broker sends the will; a
plain reset only gives "session taken over" and no will. The two boards' configs live in separate folders because
variants a to c share a `name` (the MAC suffix tells them apart), and the same name in one folder shares a build
directory. A D1 mini CH340 can garble the serial capture after an RTS reset, so read its topics from the broker.
`esphome logs --device MQTT` on a current tree needs paho-mqtt 2.x; an older venv with 1.6.1 fails, so use a venv
made from the tree's requirements.txt. A Restart press never delivered the shutdown message on any build tested.
## Shutdown message delivery (#21566)
`scripts/mqtt/shutdown/`: `sd-common.yaml` sets birth/will/shutdown payloads `hello`/`dead`/`bye` so the shutdown
message and the will cannot be confused, and takes `restart`, `disable` and `sleep` on `<name>/cmd`.
`sdrun.sh V N` (`TREE`, `P32` and `P66` in the environment) compiles and flashes the ESP32 and D1 mini, restarts each N times, disables MQTT once and deep sleeps the ESP32 three
times (never the D1 mini: without the GPIO16 to RST wire it never wakes); `match.py OUT` counts a `bye` within 5 s of
each command. Dev: ESP32 0/10 restarts, D1 mini 1 to 3/10. Put the broker address (`broker_ip`) in the secrets.yaml next to
the included package, and quote `"${name}/status"` inside flow mappings.
Results: https://github.com/esphome/esphome/pull/21566#issuecomment-6381448061
Retest at c9cf3c2813 (shutdown message sent at QoS 1, teardown waits for the broker's ack): 10/10 restarts on both
boards and 3/3 deep sleeps, against 1/10, 3/10 and 0/3 on base. An earlier 100 ms hold gave 3/10, 6/10 and 2/3, so
judge a delivery fix by counts over 10 or more restarts, never one or two presses.
Results: https://github.com/esphome/esphome/pull/21566#issuecomment-6382076613
## MQTT discovery against a throwaway Home Assistant (#21956)
Run a Home Assistant dev install with its own config directory (`hass -c <scratch>/ha`) holding `http:
server_port: 8129`, `api:`, `config:`, `onboarding:` and MQTT debug logging, plus a local mosquitto on 1883. In
`scripts/mqtt/ha_discovery/`, `onboard.py DIR` creates a generated test user (the credentials stay in DIR) and a
token, `flow.py TOKENFILE` adds the MQTT entry (the `protocol` and `other_settings: {set_client_cert: false,
set_ca_cert: "off", transport: tcp}` fields are required), and `hadrive.py TOKENFILE NAME` reads the device's time,
date and datetime entities, calls `set_value` on each and reads again; it exits 1 on a missing entity, a failed
call or a state that does not read back the value that was set. The three share the REST calls in `ha_rest.py`. `dt-common.yaml` is the device side (classic ESP32, three
template datetime entities, `${broker}`).
- The HA dev branch keeps a YAML port change as a pending HTTP config and reverts it after 5 minutes. Before
starting HA again, set `data.stable.server_port` to 8129 and `data.pending` to null in `.storage/http`.
- ESPHome MQTT unique ids are name based: clear the previous build's retained discovery (`mosquitto_pub -r -n` on
each config topic) and expect the entity ids of the first build.
## mqtt.disable and broker drops on ESP-IDF (#22230)
`scripts/mqtt/disable/disable-common.yaml` disables MQTT for 30 s every 60 s (every third cycle starts with fast
toggles, a disable while connecting), publishes a tick every 2 s and logs `EV CONNECT`, `EV DISCONNECT` and
`EV MSG`. `run.sh LABEL outage|drop SECONDS` (env `TREE`, `PORT`, `SC`, `PY`, `BROKER`, `BROKER_PORT`) starts a
private mosquitto so it can stop and start it, flashes and captures:
- `outage` publishes to `md<LABEL>/in` every second and stops the broker inside a disabled window; `analyze.py`
prints per window the device connects, inbound messages, broker connects, ticks that reached the broker and the
time from enable to connect, and fails the run on a device connect or an inbound message inside a window.
- `drop` stops the broker 6 s after every enable for 15 s. This is the case that found a watchdog reset: calling
`esp_mqtt_client_stop()` while the esp-mqtt task sleeps in WAIT_RECONNECT blocks the caller for up to
reconnect_timeout/2 (5 s), 6 of 6 task watchdog resets on an S3 and a C6.
Both modes also fail when the device never connects or the broker was never stopped, and `outage` when no inbound
message arrived.
Use the host's current address for `BROKER`: a stale one gives `esp-tls select() timeout`. Before #22230 the client
reconnects on its own during disable (14 of 16 windows). Results:
https://github.com/esphome/esphome/pull/22230#issuecomment-6614854671
## Retained message burst at connect (#22200)
`scripts/mqtt/retained_burst/`: `burst-topics.yaml` (a package) subscribes 25 `on_message` topics plus 15 switch
command topics, `burst-common.yaml` logs the counts 15 s after the connect, and `seed.sh BROKER_PORT` leaves all 40 retained on a local mosquitto (`seed.sh BROKER_PORT clear` removes them).
`run.sh LABEL BOOTS` (env `TREE`, `PORT`, `SC`, `PY`, `BROKER`, `BROKER_PORT`, default board an ESP32-C3) resets the
board BOOTS times and prints `RESULT got=x/25 switches_on=y/15` and any `Dropped` lines per boot; it passes only with
40 of 40 on every boot. Before #22200 the C3 dropped exactly 49 events (80 events minus 31 slots): the main loop
drains nothing during the burst.
## Forced reconnect mid-burst (#22248)
`scripts/mqtt/reconnect/`: `kick-common.yaml` includes the same `burst-topics.yaml` and counts per connection with
a `mode: restart` script on `on_connect`, logging `RESULT` 6 s after each connect. It and `run.sh` use files from
`../retained_burst/`, so copy the whole `mqtt/` directory to the scratch directory. `kick.py BROKER_LOG BROKER_PORT
PREFIX CYCLES` tails the broker log and takes over the device's client id 0 to 400 ms after every other connect
(mosquitto drops it with "session taken over"), then leaves the next connection alone for 8 s and ends it. It
starts by kicking the connection that is already up and skips its own connections (from 127.0.0.1 with the same id).
`run.sh LABEL CYCLES` (env as above plus `BROKER_LOG`) seeds, flashes, waits for the first connect and runs the
kicker. The device counts its first connection as CONN 1, so the kicked ones are the even CONN numbers and the
left-alone ones the odd numbers from 3 up; kick.py prints each left-alone connection with its time and CONN number,
and `judge.py` pairs those with the RESULT lines by time and passes when every one has `got=25/25`. A reset after
the first connect fails the run. Retained switch commands fire `on_turn_on` only on the first connection, so
`switches_on` is not judged.
@@ -1,103 +0,0 @@
# nrf52
## nRF52840 dongle boards (#19009, #20814)
Test config: the two LEDs as inverted GPIO outputs, the button as an inverted pull-up binary sensor, a
10 s alive interval. To retest the nrfutil download path, move the cached `sdk-nrf/nrfutil` aside first.
## ItsyBitsy over UF2 when serial DFU fails (#20481)
Serial DFU to the ItsyBitsy nRF52840 fails about half the time ("Target is not in DFU mode"). Reliable path: a
1200 baud touch on the app port, wait for the `ITSY840BOOT` volume, convert `zephyr/zephyr.hex` with the SDK's
`zephyr/scripts/build/uf2conv.py -f 0xADA52840 -c` and copy the .uf2 to the volume (the copy ends in an I/O error
when the board reboots, which is normal). macOS BLE scans give UUIDs, not MAC addresses.
## zephyr_ble_server connection slot under reordered callbacks (#21723)
`scripts/zephyr_ble_server`: the ItsyBitsy runs `server.yaml` (one connection slot) and an ESP32 runs `client.yaml`,
which connects, drops the link 300 ms later and reconnects as soon as the server advertises again. `run.sh NAME 90`
flashes the UF2, counts the server's `Connected`/`Disconnected`/`Advertising` lines and the client's connects,
and ends with PASS (more than one server connection) or FAIL; an empty capture or a silent client fails the setup.
- The connect and disconnect callbacks each `defer()` to the main loop and the bug needs the disconnect handled
first, which cannot be forced over the air. Force it with a test-only patch on both trees: replace the connect
callback's `defer(...)` with `set_timeout(5000, ...)`. A leaked reference then shows as one connection and nothing
after it (the dump still lists the closed link); a fixed build keeps cycling (17 in 90 s on #21723).
- `dfu: true` makes the next flash a 1200 baud touch; an app built without it needs a double tap on RESET. The
Zephyr app enumerates as `2fe3:0100`, the bootloader as `239a:0051`, so find the board by its USB serial number.
- macOS is a poor central here: it keeps old bonds with a board (`Peer removed pairing information` on connect)
and clearing them is a system setting. Use an ESP32 `ble_client`; the server's random static address comes from
its own log.
## SMP over UDP OTA over Thread, with reset faults (#17245, #21910)
Setup: a Thread border router (see openthread.md) whose OMR prefix the laptop routes to, and an ItsyBitsy nRF52840
(the Adafruit bootloader carries the MCUboot layout; the nRF52840 Dongle's Open DFU bootloader is rejected for
`zephyr_mcumgr` OTA). `scripts/smp_udp_ota/smp-udp-ota-dut.yaml` joins the network with `force_dataset: true` and
logs its build label every 10 s. The first image goes in over UF2, every later one with
`ota.sh MODE YAML VER ADDR` to the device's OMR address. A full image (about 380 KB) takes about 130 s.
- An ESP Thread Border Router board running ESPHome `openthread: border_router: rcp:` works as the border router
(pins in `boards.md`). Give both it and the device a fixed dataset with `force_dataset: true`; each keeps an old
stored dataset otherwise. The host learns the route to the OMR /64 from the border router's RA; ping the
device's OMR address before the first upload.
- Install the smpclient version pinned in requirements. An older one fails with `unexpected keyword argument
'timeout_s'` and a missing `get_max_cbor_and_data_size`, which looks like a PR bug. Check the version with the
Python of the venv that runs ESPHome, not a system pip.
- The build holds two `zephyr.uf2` files. Copy `.pioenvs/<name>/zephyr/zephyr.uf2` (the app, from 0x26000 up,
about 827 KB). `mcuboot/zephyr/zephyr.uf2` (about 70 KB) lands on the app slot and the board stops enumerating;
double tap RESET and copy the right one.
- To log the device's addresses, format `otIp6GetUnicastAddresses()` by hand: `network::IPAddress::str_to()`
does not link on nRF52 (no `inet_ntop`).
- A new image refuses the next upload (`No free slot. Testing mode but not confirmed yet.`) until it confirms itself.
Wait about 4 minutes between uploads.
- An image that is already in the secondary slot is only marked and reset (a few seconds). Change `ver` for every
upload that has to transfer, and expect a host-only change to rebuild byte-identical firmware.
- `inject.py` faults the reset on the host: `lostreply` drops the reply of a reset the device got, `lostreq` drops the
first request, `lostreq2` drops every reset. The device resets after a short delay, so even after a lost reply the
client usually still finds the old image running with the new one pending and resends the reset to the old image,
which is safe. `lostreq2` must end in an error with the old image still running. `ota.sh` ends with `check.sh`,
which prints PASS or FAIL for the mode, and `inject.py` fails the run when no reset was faulted.
- Without `libc_nano` the config overflows the 396,800 B slot by about 4 KB with Zephyr's TCP stack linked (about
11 KB of it, unused by SMP over UDP). With TCP left out (#21910) it fits with the full libc. A config with `api:`
keeps TCP.
- **The real OTA size limit is lower than the link limit.** The nRF Connect SDK partition manager overrides the device
tree, so read `partitions.yml` in the build directory, not `zephyr.dts`. On the ItsyBitsy layout `mcuboot_primary` is
0x61000 (97 sectors of 4 KB, 0x2f000 to 0x90000) and the app partition 0x60e00 (396,800 B); `mcuboot_secondary`
is 0x90000 to 0xf1000 and `settings_storage` 0xf2000 to 0xf4000. MCUboot swap using move keeps one sector for
its trailer and one for the move, so it only swaps in an image up to (97 - 1 - 1) × 4 KB = 389,120 B
(`app_max_sectors()` and `app_max_size()` in bootutil `swap_move.c`). An image between 389,120 and 396,800 B links,
uploads and the CLI reports `Successfully uploaded program`, but MCUboot never swaps it in: it stays pending in the
secondary slot, and every later upload and the SMP image erase fail with `NO_FREE_SLOT`. OTA stays stuck until
the slot is cleared over USB. Measured: 388,787 B swapped in, 392,155 B did not. `ota.sh` checks `app_update.bin`
against this limit with `mcuboot_slot.py limit` before it uploads, and afterwards asks the device which image runs
(`mcuboot_slot.py active`, by the image's SHA-256), since the CLI's exit code alone is not proof. That check passes once the
new image runs and says whether it has confirmed itself; add `--expect confirmed --wait 300` to prove it stays.
- With #17245 at 03d45d1aaa the build itself fails above the limit (`The application image is N bytes, but MCUboot
can only swap in L bytes on this board`), and after a confirmed reset the client waits for the device and logs
`runs the new image` or fails with `rebooted but did not swap in the new image`. After a dropped reset reply it still
ends with `The reboot of ... is not confirmed` without that wait, so `ota.sh`'s own image check is what proves those
runs.
- Clearing a stuck pending image: the SMP image erase is refused while the image is pending, and resets do not help.
Over USB, touch the app's CDC port at 1200 baud to enter the UF2 bootloader, then copy the 16-block UF2 from
`mcuboot_slot.py blank-uf2 BUILD OUT`, which writes 0xFF over the secondary slot's header page (`mcuboot_secondary`
in `partitions.yml`, 0x90000 on the ItsyBitsy). The bootloader resets on its own once the last block is written
(`cp` may report an I/O error then, which is normal), MCUboot finds no image header and clears the slot, and the
image states show slot 0 only.
- Over USB, the Adafruit UF2 bootloader only accepts blocks inside its app area (its `CURRENT.UF2` maps 0x1000 to
0xE9000). A UF2 with a block outside that area is never completed, and the bootloader then ignores every
later file, even a good app UF2, until a physical reset (double tap RESET or replug). Keep hand-made UF2 writes inside the app area.
- Results: https://github.com/esphome/esphome/pull/17245#issuecomment-6516152182,
https://github.com/esphome/esphome/pull/17245#issuecomment-6518292041 (swap limit),
https://github.com/esphome/esphome/pull/17245#issuecomment-6519010038 (retest)
## TCP stack only when a component uses TCP (#21910)
`scripts/nrf52_tcp_probe/tcp-probe.yaml` joins the test Thread network with no TCP user and opens a TCP and a UDP
socket twice from an interval. Build it per tree with `-s name NAME`, flash over UF2, capture the USB log, then
`check.sh BUILD CAPTURE`: it reads `CONFIG_NET_TCP` and the packet and buffer counts from
`.pioenvs/<name>/zephyr/zephyr/.config` and wants `tcp null udp ok` twice plus the `TCP stack not built` error exactly
once on a build without TCP, or `tcp ok udp ok` twice and no error with it. Add `api:` to see TCP and the larger pools
come back, and connect with `apicheck.py ADDR` over Thread. Measured on the ItsyBitsy: 12.9 KB less flash and 17.1 KB
less RAM without TCP (Zephyr's default pools, 16/16 instead of 24/48), and SMP over UDP OTA still works with them.
Results: https://github.com/esphome/esphome/pull/21910#issuecomment-6518287139
@@ -1,64 +0,0 @@
# online_image
## online_image stalled downloads (#20594)
One classic ESP32, both frameworks (the ESP32 Arduino build also uses `http_request_idf.cpp`). The host
serves the images: `scripts/online_image/make_images.py <www>` writes 16x16 BMP/PNG/JPEG/QOI plus an 8 bit
palette BMP with a 1078 byte header; `scripts/online_image/oi_server.py <www> 8765 <log>` answers one
misbehaviour per path name (`ok`, `truncated`, `large_header`, `empty`, `stall` holds the socket 40 s,
`closed_early`, `slow` pauses 2.5 s, `chunked`, `chunked_cut`, `noclen`, `huge` claims 20 MB) with an ETag
and a 304 on If-None-Match. `templates/online-image-dut.yaml` has two AUTO-format images (default and
256 byte buffer), API actions `fetch`/`fetch_small` (set_url with `update: false`, then component.update)
and `refetch`/`refetch_small` (component.update only, keeps the cache headers), and a restart button.
`scripts/online_image/drive.py <device ip> <api key> <capture> http://<host ip>:8765 pr|base` runs the
case list over aioesphomeapi and judges each from the serial capture. ESP-IDF facts: a stalled server
ends with `Error downloading image: -28679` (EAGAIN) after the transport timeout, an early close with
`-1`, both before and after the PR; a body without Content-Length and without chunking reads as complete
(Size: 0) and finishes. A build without the fix hangs on the truncated, oversized header, empty, chunked PNG
and cut chunked cases and every later update logs `Image already being updated.`, so a baseline run needs
a reboot per group, the driver's 45 s cap per case, and an outer `timeout` that covers the whole list.
A case expected as `any` passes on `finished` or `error`, never on no outcome.
## PNG decode time limit (#21364, #21391)
The same server also serves any plain file in its www directory by name (404 for a missing file or a path
outside it). `scripts/online_image/make_big_pngs.py <www>` (after `make_images.py`) writes a 320x240 gradient (618 B, also as `ok.png` so the misbehaviour cases carry a
real multi-row PNG), a flat 640x480 PNG (1.6 KB for 307200 pixels), 231 KB of noise and a JPEG. The device is
`templates/online-image-dut.yaml` with `type: BINARY` on the main image (a 640x480 RGB565 does not fit a classic
ESP32 without PSRAM) and `debug` loop time and heap sensors at 2 s; the 256 byte buffer image stays RGB565, so do
not point big images at it (out of memory on every build). `scripts/online_image/pngdrive.py HOST KEY LOGFILE
BASEURL LABEL` (default case set `png`; `CASES=short` for the six case list) calls the actions, waits for the
finished or error line and reports the case time, the highest loop time and the lowest free heap. The per pass `online_image.image took a long time` values come from
the serial capture and only print on a new maximum, so read the first fetch of each image. The pass that decodes a
whole buffer is the decoder cost (before the change 510 ms gradient and 1980 ms flat, after it 77 and 140 ms); for
the noisy PNG the longest pass is the blocking 64 KB read on both builds (0.7 to 3.7 s). Alternate PR, base, PR
for a timing claim.
For a replacement PR, compare against the parent PR head, not dev. `CASES=noise` fetches the noisy PNG three times
(run it right after a boot, alternating builds); `CASES=end` runs flat and gradient as plain, `noclen_`, `chunked_`,
`half_` and `stall_` through the prefixed server cases below.
## JPEG decoded as it downloads (#21342)
`oi_server.py` serves prefixed cases on any file: `half_<file>` (first half, matching Content-Length),
`noclen_<file>` (close delimited), `chunked_<file>` (1 KB chunks), `stall_<file>` (a third, then the socket held
40 s). `scripts/online_image/make_jpegs.py <www>` writes noise, gradient, 12 KB EXIF and progressive JPEGs. Device:
`templates/online-image-dut.yaml` with `type: BINARY` on both entities and `buffer_size: 4096` on the second;
`CASES=jpeg scripts/online_image/pngdrive.py HOST KEY LOGFILE BASEURL LABEL` runs the JPEG list; every case set
prints case time, highest loop time and lowest free heap. Before the change a JPEG needs a contiguous block of its file size (233 KB never
allocates on a classic ESP32, and after a few failures 69 KB does not either until a reboot); after it the 64 KB
buffer stays 64 KB and 4 KB is enough for a baseline JPEG. The first pass still reads up to `buffer_size` in one
blocking read, so the 64 KB entity blocks 1.7 to 4 s and the 4 KB one 272 ms at most; judge the decode budget on
the small buffer entity. Already on dev: a JPEG without Content-Length (plain or chunked) ends with `Could not open
image for decoding: 4` then `Invalid type`.
## BMP and QOI decode time limit (#21392)
Use a wired board (`templates/online-image-s3-eth-dut.yaml`: Waveshare ESP32-S3-ETH, W5500, PSRAM, `type: RGB565`)
rather than a classic ESP32 on Wi-Fi: with a weak link the reads block up to the 4.5 s timeout and the per case loop
numbers are noise. `scripts/online_image/make_bmp_qoi.py <www>` writes 1 bit BMP 640x480, 8 and 24 bit BMP 320x240,
QOI 640x480 one colour (all runs) and checkerboard, QOI 320x240 gradient and noise. `pngdrive.py` with
`CASES=bmpqoi` runs each as plain, `noclen_`, `chunked_`, `half_` plus stalls. The `loop_time` sensor sits at 75
to 160 ms even for a 16x16 image, so for decode passes use `scripts/online_image/firstpass.py HOST KEY BASEURL
LABEL IMAGE...`: it reboots the device before each fetch and reports that fetch's `took a long time` maximum. A
`half_` file with matching Content-Length reports `download finished` with "not caching it" on dev too.
@@ -1,5 +0,0 @@
# openthread
## Thread border router (#18104)
See boards.md for the ESP Thread BR board. Check that the H2 answers Spinel before blaming a PR.
@@ -1,86 +0,0 @@
# ota
## OTA overlap and lock (#20588), OTA timeouts (#19041), deflate (#19037)
All overlap orders (a web upload during a native OTA and the reverse) must be refused; the lock release
after an interrupted web upload waits about 14 s (ESP8266) or 7 s (ESP-IDF) for disconnect detection. A
refused web client on `web_server_idf` never gets the busy reply; the connection drops at reboot.
`pkill -f "a\|b"` does not alternate; use two pkills.
## OTA upload timing A/B (#21639, #21641, #21642)
`scripts/ota_timing/run.sh N PHASE...` times native OTA uploads per build (phase) and per board. It builds every
board from `TREE_<PHASE>`, does one warm-up upload per board (it installs the phase's build and is left out of the
results), checks over the API that each board reports the compile time from that build's `build_info.json`
(`apiinfo.py`), then runs N rounds of every mode on every board. Boards are interleaved per round so they share the
same air; put a nearby ESP32 on the same Wi-Fi in `BOARDS` as a network control. `summ.py` prints medians: never
judge from single runs, slow Wi-Fi gave 33 to 235 s for the same upload in one night.
- `otatime.py` drives `espota2.run_ota()` from the tree on `PYTHONPATH` and prints one `RESULT` line with the
`Update took` split, the compressed size, whether UDP was used and the time at each tenth of the upload.
An upload that leaves no `RESULT` line (board gone, script crash, timeout) is recorded as `rc: -1`, and `summ.py`
fails when a board and mode has fewer than N rows or an upload time cannot be read.
- Boards with an `api: encryption: key` also encrypt OTA: set `API_KEY` for `otatime.py` and `apiinfo.py`. LibreTiny
LN882H listens for OTA on 8820, not 8892; BK72xx and RTL87xx use 8892.
- Raw mode leaves `CLIENT_FEATURE_SUPPORTS_DEFLATE` out of the client's offer. Never switch deflate off after the
offer (`if deflate and 0:`): once the device accepted deflate it expects a deflate stream.
- `-tcp` modes make `espota2._loss_reason` return None, so the client asks to stay on TCP. Clearing
`CLIENT_FEATURE_SUPPORTS_UDP` instead desyncs the handshake (`receiving UDP token response: timed out`).
- LibreTiny trimmed UF2 (#21642): the CLI sends what `esphome.components.libretiny.uf2.device_ota_uf2()` returns for
`firmware.uf2`; that module only exists with #21642, so on older trees the full UF2 goes out. Compare the sizes
in the `Compressed to` lines, and rely on the API compile time check to show that the trimmed image booted.
`receiving chunk result: Unknown error from ESP` is error 0xFF sent by the device, not a dropped connection. The
device sends it for a decode or flash write error, and also when no data arrives for 105 s, so on a weak link it
usually means a stall. A failure about 105 s after the last progress, or the same error on a raw upload, points to
the link; to be sure, capture the device log (`Inflate err`, `Inflate overrun`, `No data received`).
Results: https://github.com/esphome/esphome/issues/21639#issuecomment-6409628227 (dev and LibreTiny 1.14.0 on a
CB3S), https://github.com/esphome/esphome/pull/21642#issuecomment-6412972562 (trimmed UF2 on CB3S, BK7238 and BW15),
https://github.com/esphome/esphome/pull/21641#issuecomment-6412976859 (new decoder on the same three).
## On-device inflate benchmark (#21639, #21641)
`scripts/ota_timing/inflate_bench`: `gen_streams.py NAME=IMAGE...` cuts a 128 KB slice from each image and writes
`bench_streams.hpp` with raw deflate streams (level 9, 4 KB and 32 KB windows). `bench.hpp` inflates every stream with
each ring size at least the encoder window, three times, and logs the best time plus input and output rates, then
`BENCHDONE`. `bench.sh CONFIG DEVICE` builds and uploads `bench-esp32s3.yaml` or `bench-bk72xx.yaml`, collects one pass
over syslog and fails when a case did not reach the end of its stream.
- LibreTiny defines `micros` as a macro, so the header calls `(esphome::micros)()`.
- Keep the streams near 130 KB on a BK7231N: an image with about 330 KB of extra incompressible data failed its
OTA with "Writing OTA data to flash memory failed". Use one image and `--windows 12` there.
- `bench.hpp` targets the decoder interface with `dest_limit`. #21641 drops it (the output runs into the window up
to `dest`); after that lands, remove the `dest_limit` line.
Results: https://github.com/esphome/esphome/issues/21639#issuecomment-6409786224
## Upload without a configuration (#21738)
`esphome upload --file IMAGE --device IP` with no YAML picks the OTA port from the image header and takes the password
from `--ota-password` or `ESPHOME_OTA_PASSWORD` and the key from `ESPHOME_OTA_KEY`. Test each chip family with its own
current image (`build/firmware.ota.bin` for ESP-IDF, `.pioenvs/<name>/firmware.bin` for ESP8266, `firmware.uf2` for
LibreTiny) and check the build over the API; switch one board between two builds to show a new image lands.
Point every case that should be refused before connecting at an unroutable address (192.0.2.1), never at a board: a
refusal prints no `Connecting to` line, and an image that slips through cannot reach a device. An ESP32-S3
`firmware.factory.bin` slipped through on 2026-10-27 (its bootloader header at offset 0 looks like an app), the device
reported `OTA successful` and its bootloader rejected the slot at boot; send the board its proper app image afterwards.
A factory image has the partition table magic `AA 50` at 0x8000 and the app at 0x10000.
## OTA automations on two OTA platforms (#21903)
`scripts/ota_automations/ota-automations-common.yaml` (a package) puts `esphome` and `web_server` OTA in one config,
each with all six automations (`on_begin`, `on_progress`, `on_end`, `on_abort`, `on_error`, `on_state_change`)
logging a platform tag and the argument. `run.sh esp32|esp8266 LABEL` builds, flashes by serial, and runs four cases
under one capture: a native upload, a native upload whose uploader is SIGKILLed after the first progress fire, a
web_server upload of a random 64 KB file and a web_server upload of the real image. `summ.py OUT_DIR` prints each
case's fires in order with progress collapsed to a count; diff dev against the PR.
- `web_server: ota: false` removes `/update` (404), so leave it out when the web platform is under test.
- A killed native uploader ends in `state 4` and `error 255`, not `abort`. `on_abort` only comes from a web upload
cut on the network. On ESP8266 those happen by themselves (1 in 4 uploads on dev), so count them on both builds with
`webrep.sh IP IMAGE COUNT` before blaming the PR.
- A random file through web_server gives `error 128` on the ESP32 and `error 132` on the ESP8266.
- A SIGTERM to the uploader lets it finish the transfer; use SIGKILL for the native error path.
- Results: https://github.com/esphome/esphome/pull/21903#issuecomment-6516529409
@@ -1,10 +0,0 @@
# prometheus
## Date, time and datetime metrics (#9941)
`scripts/prometheus/prom-datetime.yaml` is a D1 mini with `web_server`, `prometheus` and three optimistic template
datetime entities; `prom-datetime-tz.yaml` adds an sntp time component with `HST10` (the zone applies without a sync).
`datetime_metrics.py HOST` prints the rows of `/metrics`, sets the entities over the API to 2040 values (past 2038 on
purpose) and prints them again with their UTC reading. Dates are local midnight in ms, times ms since midnight,
datetimes ms since the epoch, so a datetime set as an instant reads the same in both zones. It exits 1 when a time
or datetime row does not hold the value it set (dates depend on the zone and are only printed).
@@ -1,30 +0,0 @@
# remote_base / remote_receiver
## Loopback on one pin, no IR hardware (#21560 to #21563)
`templates/remote_base/`: `rb-common.yaml` (API action `tx_all`, a dumper registered from `on_boot` through
`register_dumper()` standing in for an external component), `rb-txscript.yaml` (14 `remote_transmitter.transmit_*`
frames with `tx <proto>` log markers), `rb32.tmpl` and `rb66.tmpl` (`@V@` is the build label).
`scripts/remote_base/run.sh LABEL B N` (`TREE`, `P32` or `P66`, `SC` in the environment) writes the run file from the
template, builds and flashes it from `TREE` (`esphome run --no-logs`), finds the IP and runs `rbdrive.py IP N`, which segments the API log by the
markers and prints what each sent frame decoded as.
- ESP32: `remote_transmitter` and two `remote_receiver`s on the same GPIO (`allow_other_uses`), carrier 100%, no
inversion. RMT reads its own output, every frame decodes. Second receiver `dump: [nec, raw]` shows raw runs only
where no primary matched.
- ESP8266: the transmitter sends with interrupts off, so a receiver on the same pin sees nothing. `softtx.hpp`
bit-bangs frames built with each protocol's `encode()` with interrupts on, and an `interval` sets the pin back to
OUTPUT after the receiver's setup. Bit-banged NEC decodes as NEC about 2 of 3 times (timing), on every build.
- Dish never decodes in loopback on dev either. Pronto matches every frame, so raw on `dump: all` never prints.
- API log lines can drop under bursts; rerun with more rounds before calling a shortfall.
- `register_dumper()` returns nothing, so the config logs `ext dumper register called`, not whether it stuck. On dev
the list has a fixed size and a dumper beyond it is dropped with `No dumper slot` (ERROR); judge by that line and by
`ext dumper saw` counts in the `rbdrive.py` table, which only appear when the dumper is really registered.
`rbdrive.py` exits 1 when the external dumper saw no frame, so a build that rejects the registration fails the
drive; set `EXPECT_REGISTER=1` on `run.sh` to also fail the run on any `No dumper slot` line.
Results: https://github.com/esphome/esphome/pull/21563#issuecomment-6381304387
Retest of the moved stack with 5 rounds per build: https://github.com/esphome/esphome/pull/21563#issuecomment-6382075726.
A D1 mini CH340 sometimes fails the 460800 baud upload; esphome retries at 115200 by itself, but a runner that reads
only the last line sees "Failed to upload" first, so rerun before blaming the build.
@@ -1,22 +0,0 @@
# rs485_frame DLE/STX/ETX bus without a bus (#16758)
`scripts/rs485_frame`: an ESP32-C3 (logger on USB_SERIAL_JTAG) with the hub's UART on tx GPIO3 rx GPIO4 and a
simulated bus device on tx GPIO4 rx GPIO3, cross-wired through the GPIO matrix (`allow_other_uses: true` on all
four pins), 9600 baud, no wires. The simulator is polled from an `interval` and logs with the `sim` tag; the test
script logs with `hwt`.
- `simrs.hpp` builds sum16 big endian, header-inclusive frames (`10 00` stuffing, `10 10` with
`simrs::double_mode`) and logs each frame the hub sends (`RXF`) with start and end poll times, the silence since
the previous frame and the time since the simulator's own last byte. `rs-base.yaml` (board, cross-wired UARTs,
poll interval, the hub's CRC and a log line per received frame) and `buttons.yaml` are shared packages.
- Case files: `common.yaml` runs good / bad CRC / garbage / split at 25 and 150 ms / overlong / max length / two
frames in one write / a cut frame followed by a new DLE STX / a bad escape, then button presses that the hub must
hold until a `01 01` gate frame arrives (`replace_latest` keeps only the last press). `rsi2.yaml` (idle_gap gate),
`rsx.yaml` (fixed_delay gate), `rsd.yaml` (sniffer_only, double escape).
- `run.sh CASES LABEL [SECONDS]` (`CASES` is `common`, `rsi2`, `rsx` or `rsd`; `TREE`, `PORT`, `SC` in the
environment) writes a run file with its own name, builds and flashes with `esphome run --no-logs`, captures and
writes `out-rs<CASES><LABEL>.log` with time stamps and line numbers stripped. It fails without a `DONE` line or on
a crash. Diff the logs of dev and the PR; for the gate timing cases read the `RXF` lines (silence before each frame
the hub sent).
- On ESP32 at 9600 baud the default `rx_full_threshold` is 8, so a component does not see bus bytes for about 9 ms.
Queue a test frame at least 20 ms after the bus starts talking, or it collides on any idle-gap design.
@@ -1,18 +0,0 @@
# rtsp_server
## RTSP camera streaming on the Waveshare ESP32-S3-ETH (#17990)
`templates/rtsp-waveshare-s3-eth-dut.yaml` (OV5640 pins, GPIO8 camera power switch with the 1.2 s boot delay,
`rtsp_server`, logger VERBOSE for `rtsp_server`); swap the `wifi:` block for the W5500 `ethernet:` block when
the cable is in, and add `network: enable_high_performance: true` for the big TCP buffers. Flash over native
USB, capture the log with `serial_capture.py`, take the IP from the last `IP Address` line that is not
0.0.0.0 (or `dns-sd -Q <name>.local`). `scripts/rtsp_server/rtsp_client.py IP [cases]` covers play, udp,
pipeline, badreq, replay, getparam, teardown, third, stall, timeout; `rawrate2.py IP quiet|chatty|rtcp|bigbuf`
measures the raw receive rate; `measure.sh IP LABEL LOGFILE [OUTDIR]` runs the fixed set (ping, ffmpeg 12 s
twice, two ffmpeg clients, raw reader) and appends to `results.txt`; `cam_api.py IP` pulls one image over the
API; `ffmpeg -rtsp_transport tcp -i rtsp://IP:554/ -frames:v 30 -f image2 f%03d.jpg` plus Pillow checks
decoding. The 5760 byte default TCP send buffer makes the stream stall over Wi-Fi (about 1 fps, dozens of
stall drops per run); `enable_high_performance` gives several fps on Wi-Fi and removes the stalls on Ethernet.
Frame counts vary a lot between runs (auto exposure changes the JPEG size), so always measure twice. Home
Assistant's stream pipeline does not accept MJPEG over RTSP; its ffmpeg camera opens one RTSP session per
snapshot, so `max_connections` needs headroom, and go2rtc transcoding to H.264 is the way to a live view.
@@ -1,23 +0,0 @@
# scheduler
## Scheduler and loop wake A/B (#20356)
An external component whose template button arms an SDK `os_timer` (50 ms, one shot) on the ESP8266;
the callback runs in SYS context, records `millis()` and calls `set_timeout` or `defer`; the timeout
logs the elapsed time and loop count delta. Drive with an aioesphomeapi script (`subscribe_logs` plus
`button_command`). Build the same yaml twice with different names, one per tree.
## interval startup_delay and control from lambdas (#21799)
`scripts/interval/interval-common.yaml` has plain 1 s and 2.5 s intervals, a 1 s interval with `startup_delay: 5s`, a
3 s one with `startup_delay: 500ms`, and a 15 s control interval (`startup_delay: 0s`). The control interval
changes the plain 1 s interval to 500 ms with `id(i_plain).set_update_interval(500)` and `start_poller()`, then
stops it and the 5 s delayed one with `stop_poller()`. Every run logs `millis()`. `run.sh LABEL` flashes a D1 mini,
captures 40 s from boot and runs `ivsum.py`, which prints the run count, first run after boot and gaps per interval.
- Check that each delayed interval's first run comes at or after its delay, that the gaps equal the interval, that
the 500 ms change takes effect, and that nothing runs after a stop.
- The first run of an interval without a delay falls at a different time on every boot (the scheduler spreads first
runs), so do not compare those offsets between builds.
- `main.cpp` shows the class each interval gets (`IntervalTrigger` or `DelayedIntervalTrigger` on #21799).
- Results: https://github.com/esphome/esphome/pull/21799#issuecomment-6516798398
@@ -1,20 +0,0 @@
# Sensor, binary_sensor and text_sensor filter A/B (#21831, #21813, #21830)
`scripts/sensor_filters` needs only a board. `sensors.yaml` holds 29 template sensors with every offset, multiply,
clamp, NTC, calibrate_linear, delta and lambda filter shape, plus a sensor with id `x` (a value lambda that reads an
id named `x`). `sf.yaml` adds binary and text sensor lambda filters and an interval that feeds the 50 inputs of
`sf.hpp` (NaN, ±inf, -0.0, values on and across the bounds) 200 ms apart, logging one line per input with every
filter output as float bits (`-` means dropped), then `DONE`.
- `run.sh esp8266|bk72xx LABEL` writes the per-run file, builds, flashes, captures and writes `out-sf<kind><LABEL>.out`
(100 lines). Compare a PR build with dev using `cmp`: identical files mean identical filter output, including
which values were dropped. ESP8266 matters because its float math is in software.
- The template sensor ids are `flt1`, `flt2` ...: `s8` and `s16` clash with ESP8266 SDK typedefs.
- Grep the build's `main.cpp` for the new code (for example `clamp_filter_value`, `delta_passes`, generated filter
functions) to prove the build came from the PR tree.
- `BASELINE` sets the delta baseline: a lambda works everywhere, a plain number crashed before #21811.
- Between boards the only difference is the sign of the NaN that `to_ntc_temperature` returns for 0 Ω (libm), on dev
too, so compare builds on the same board.
- The ESP8266 esptool stub can hit serial noise on a CH340 and the BK7238 link sometimes times out once; the runner
retries.
- Results: https://github.com/esphome/esphome/pull/21831#issuecomment-6490999545
@@ -1,36 +0,0 @@
# sigma_delta speaker and rtttl sample taps
## Pulse density of the speaker pin, measured inside the chip (ESP32-P4, #18702)
Nothing is wired to the pin. `scripts/sigma_delta/sdprobe.hpp` calls `gpio_input_enable()` on the SDM output pin,
and a core 0 task reads it with `gpio_get_level()` 2000 times per window, with pseudo-random gaps of 0 to 255 cycles
(xorshift) that decorrelate the samples from the 1 MHz modulator. One window is about 2 ms and the density noise is
about 0.5% sd. The expected duty for an int8 density d is (d + 128) / 256, so 16-bit PCM at +50% reads 75%, 0 reads
50%, and full scale reads 99.6% or 0%.
The same header has:
- a core 0 feeder task (DC, sine, stereo L/R, a burst of N frames, any 8/16/24/32 bit mono or stereo format) that
calls `speaker->play(..., 20 ms)`;
- a played-frame counter on `add_audio_output_callback()`: frames per second over 4 s matches the rounding of the
10 MHz timer exactly;
- a CPU probe: a priority 10 task pinned to the loop core spins for 200 ms, and the iterations while playing against
idle give the interrupt share (44.1 kHz cost 20% of core 1).
`gen.py tpl.yaml > NAME.yaml` builds the whole sequence (the device name comes from `esphome -s name NAME`): DC levels,
volume, mute, formats, 2 Hz and 50 Hz sines with DUMP lines, sample rates, underrun, stop mid-play, finish, rtttl and a
play/stop hammer. `gen2.py` (both share the step helpers in `steps.py`) builds the inverted pin run (set the speaker
pin to `{number: GPIO21, inverted: true}` in a copy of `tpl.yaml`) plus the CPU cost per rate. `run.sh LABEL
[gen|gen2]` generates, builds, flashes, captures with `--ms` until `ALLDONE` and prints the `RES` lines; for `gen` it
then runs `an.py`, which fits the sines and prints the level edges of the underrun, stop and finish dumps. GPIO21 is
free on the Waveshare ESP32-P4 Module DEV KIT. Long operation warnings in the log come from the probe's own lambdas.
## rtttl click measurement (#22075)
`scripts/rtttl_edge_tap/edgetap.hpp`: `EdgeTap`, a pass-through `speaker::Speaker` that forwards to the real speaker
and reads the int16 samples rtttl writes. `rtttl.set_speaker()` it from a lambda, and call `sync()` from an
`interval: 10ms`, because `is_running()` and `is_stopped()` read the base class state. Use tunes with a rest between
every note, so a note is a run of samples between runs of 8 or more zeros. It logs each note's onset and release
level (the largest of the first or last 4 samples as a share of the note's peak): dev about 95%, the 32-sample fade
at most 12.5%. `rtttl-edge-tap-dut.yaml` is the AUX-2 config with a USB speaker as the mixer output (it needs the
AUX-2 package next to it, see [usb_audio.md](usb_audio.md)); `run.sh LABEL` plays eight tunes and prints the note
reports. Any speaker works the same way: wrap the one rtttl writes to.
@@ -1,75 +0,0 @@
# Simulated chips on the bus, fake Home Assistant, static buffers
`scripts/sim_buses/` and `scripts/static_buffer/`. Each header is added with `esphome: includes:` and wired in an
`on_boot` lambda, so no chip is needed. The wrappers take the real bus or SPI delegate and pass through every
address they do not simulate.
- `lcdsim.hpp`: `LcdSimBus`, an `i2c::I2CBus` wrapper that plays PCF8574 backpacks (P0 RS, P2 EN, P4 to P7 D4 to D7)
driving HD44780 controllers. It decodes the EN-strobed nibbles and rebuilds the rows written after each 0x80 and
0xC0 address command. `add()` up to three addresses, hand it to each `lcd_pcf8574` with `set_i2c_bus()` at
`on_boot` priority 800, and call `report()` from an interval. `lcd_an.py SERIAL` checks the rows against the
patterns its docstring lists (0x27 20x4, 0x26 16x2, 0x25 64x4), and fails on a display whose frame count does not
grow between its first and last report, on a segment longer than its rows or on
data past the 128 byte segment buffer, which the report counts as `overflow`, on a report from an address it does
not expect, or on any read (`reads`; the driver never reads, so the simulator NACKs them). A 64x4 display hangs the
code before #22331 in
setup.
- HT16K33: use `templates/i2c_fake/htfake.hpp` with its test runner (see [fake_i2c.md](fake_i2c.md)).
- `mxsim.hpp`: `MxSniff`, an `spi::SPIDelegate` in front of the real one that keeps what each MAX7219 in a chain
latches. Swap it in at `on_boot` priority 399 through `DelegatePeek::of(id(x))`:
`auto &d = DelegatePeek::of(id(x)); d = new MxSniff(d, chips);`. `mx_an.py SERIAL CHAIN...`
summarizes the reports, CHAIN being each name passed to `report()`, and fails on a named chain with no report line,
on malformed transactions (byte count not two per chip, or a partial byte from `write()` or
`write_cmd_addr_data()`, which are recorded and forwarded too), on a named chain with fewer than two report lines,
or a chain whose transaction count stays 0 or stops growing, and prints PASS otherwise.
- `spysim.hpp`: the same delegate trick (both headers carry `DelegatePeek`, so one config can include both), logging length and FNV-1a hash of every transaction over 1000 bytes (whole
frames, used for `pixoo`). `write()` and `write_cmd_addr_data()` are hashed and forwarded like `write_array()`;
a partial byte or a bus width other than 1 is hashed as whole bytes, so the SPY line carries `odd`, the count of
such transactions, and a dev vs PR hash match only holds when `odd` is 0 on both.
- `pisim.hpp`: drives two `packet_interface` stacks on cross-wired UARTs through `top()`, with payloads whose bytes
are a function of their index so every byte is checked, and the index and length each side sent (last 256) so a
truncated or split packet, or one whose slot a later index reused, counts as `rx_bad`. Send indices 0, 1, 2 and so
on from each side: a skipped index counts as `rx_lost` and an old or repeated one as `rx_bad`. `report(tag, true)` once both links are idle ends each
line in PASS only when that side received every packet the peer sent intact and the peer had no send refused;
`missing` is the rest, packets still in flight or lost at the tail. `packet_transport` drops packets carrying its own device
name, so a one-board test must use the layers directly.
- `hcsim.hpp`: a software SN74HC165 chain on ESP-IDF (data GPIO6, clock GPIO7, load GPIO10). A falling load edge
latches the pattern and each rising clock edge drives the next bit onto the data pad, which is in
`GPIO_MODE_INPUT_OUTPUT` so the component reads it from the same pin. Call `hcsim::report(label, loads0, clocks0)`
after each window with `hcsim::loads` and `hcsim::clocks` from its start; it logs `INVALID` instead of a result
when the GPIO or interrupt setup failed or the window saw no load or no clock edge, so a dead simulator cannot pass
as a wrong but steady pattern.
- `ledprobe.hpp`: samples a status LED (or any output) pin every 2 ms from an `esp_timer`, off the loop task, and
prints blink count, on time, period and the longest gap per window. It measures `status_led` while the loop is
blocked (#16407). Pass `ledprobe::n` from the window start as the mark; a window with more than 400 edges logs
`INVALID` and no result line instead of passing for a stalled LED. So does every window when the pin or timer
setup failed or the timer has not sampled for 100 ms, so a dead probe cannot read as a quiet LED.
- `fakeha.py HOST OUT_PREFIX`: an aioesphomeapi client standing in for Home Assistant for `homeassistant` select
mirrors. It answers state subscriptions from a table, pushes option and state changes (full, overfull, quoted,
unparseable), checks each step through a "Dump" button, captures the action calls, churns 600 option updates
while watching the heap, and checks the entity options after a reconnect. A step fails when either DUMP line is
missing, and a rejected update also needs the device's rejection log line, so an update that never arrived cannot
pass. Exits 1 on a failed step and prints PASS otherwise.
- `wizard_drive.py HOST`: finishes the device wizard through aioesphomeapi 46.28 (`device_wizard`,
`wizard_input_set`), answers the subscriptions the inputs create and checks the values reached the entities.
## Static buffers (`cg.static_buffer`)
`scripts/static_buffer/` holds two local external components and `static-buffer-dut.yaml`, which loads them:
- `sbtest` allocates three buffers with `cg.static_buffer` (37 `uint8_t`, 5 `uint32_t`, and `const char *` sized by
a C++ expression) and checks at setup that they are zeroed and aligned, then fills each completely; at
`dump_config()` it checks no other instance's fill reached them. Two instances prove the buffers are distinct.
Both `SBTEST` lines end in `PASS` or `FAIL`; the `dump_config()` one passes only when the setup checks passed too.
- `sbpsram` asks for `psram=True` and uses the pointer codegen hands it: the static buffer without PSRAM, or a
zeroed `psram_buffer<T>()` with a `psram:` block, which logs `external=1` (nullptr if the allocation failed).
It also gets a plain 8 word `uint32_t` static buffer, which must be non-null, aligned and zeroed at start and read
back its fill (`plain=1`). Its `dump_config()` line ends in `PASS` only when both readbacks match, both buffers
were zeroed at start and, with PSRAM, the PSRAM one is in external RAM.
## Gotchas
- Some "classic" devkits with a CP2102N carry an ESP32-PICO-D4. GPIO16 and GPIO17 are its flash pins, and an
ESP-IDF build that drives them hits the interrupt watchdog. Use `board: pico32` and GPIO9/GPIO10.
- An `addressable_light` display writes nothing until its light is turned on.
- Before calling a rebased PR's change trivial, diff the PR's own diff (head against its parent) old against new: a
move that looks like a merge only can carry real commits from below.
@@ -1,62 +0,0 @@
# speaker
## Media player pipeline tasks (#21203)
The `speaker` media player platform (`speaker/media_player/`) creates `ann_read`, `ann_decode`, `med_read` and
`med_decode` FreeRTOS tasks on every play and deletes them after a stop. The AUX-2 and sendspin packages use the
`speaker_source` player instead, which has its own pipeline and never runs that code, so a test of
`speaker/media_player/*` has to swap the player: `templates/aux-2-preprod-speaker-player-dut.yaml` removes the
package's `external_media_player` with `id: !remove` and adds a `speaker` platform player on the package's resampler
speakers, plus a "Task names" button whose lambda calls `xTaskGetHandle()` on the four names and logs internal free
heap. Serve FLAC files from the host (`ffmpeg -f lavfi -i "sine=frequency=440:duration=90" -ac 2 -ar 48000 -c:a flac
media90.flac`, a 3 s mono one for announcements, `python3 -m http.server 8765 --directory www`); `audio_http`
refuses WAV and MP3. `scripts/speaker_media_player/cases.sh HOST KEY MEDIA_URL ANN_URL CAPTURE LABEL` runs three
cycles through `drive.py` (`play:URL | ann:URL | stop | press:NAME | wait:S` on one API connection) with the probe
pressed idle, during media, during the announcement, after it and after the stop. Pass: idle none, media `med_*`
only, announcement all four, after stop none, every cycle. API commands land a second or two late over Wi-Fi, so read
the probe against the `State changed to` lines rather than the driver's timestamps. Internal free heap after a stop
moved by 2.5 kB between two boots of the same build, so a heap delta needs more than one boot per build. Results:
https://github.com/esphome/esphome/pull/21203#issuecomment-6299581943
## Streamed TTS with a pause (#21090, #21091)
Home Assistant streams TTS while it is still being generated, so the player must start on the first part instead of
waiting for the whole file. `scripts/speaker_tts_pause/`:
- `mk.py INTRO_AUDIO CONT_AUDIO www/s1.flac` builds one 48 kHz mono FLAC stream (the intro padded to a 4096-sample
frame boundary, then the continuation) and writes the byte offset of the split to `s1.flac.cut`. Make the intro
with any TTS, e.g. `say -o intro.aiff "..."` on macOS; build a short one (`s1`) and a long one (`s2`).
- `srv.py PORT www` serves the file chunked: the header and intro at once, then it holds the connection open for
`PAUSE` seconds (8), then the rest.
- `tts-common.yaml` swaps the AUX-2's `speaker_source` player for the `speaker` platform player and counts played
frames with `add_audio_output_callback` on both resampler speakers into the counters in `frames.h` (one `[frames`
log line per change, read over serial with `--ms`). Its `on_boot` must be a list entry: a dict `on_boot` replaces
the package's list and the AUX-2 never starts Wi-Fi or Ethernet.
- `run.sh LABEL=TREE...` flashes each build and drives two short-intro and two long-intro announcements and one
media play through `scripts/speaker_media_player/drive.py` (set `DRIVE` when running from a scratch copy); `an.py`
prints first audio, the server's send times and how much of the intro played before the rest arrived, per request.
A request fails when it never played the whole intro or stopped short of 95 % of the stream.
Before the two PRs the player waited for the rest of the stream (8.2 s) for both a 22.5 KB and a 50 KB intro; with
both it starts at about 1 s.
## Voice PE wake word audio (#21885)
`scripts/voice_wake_word_audio/va.py HOST KEY OUTDIR accept,reject,timeout` stands in for Home Assistant
(aioesphomeapi 46.27.0 or later, `wake_word_audio=True`), answers each run by mode and saves both channels as WAV;
`locate.py OUTDIR` finds the played phrase in them by envelope cross-correlation against `wake16k.wav`.
`run.sh HOST TAG [ROUNDS]` runs reject and timeout rounds while playing the phrase every 9 s, starting once `va.py`
is READY. `va.py` fails a START before READY or during a run, and `run.sh`, `stale.py` and `mww.py` fail at once
when the player fails or hangs for 30 s.
- Give the test build its own API key so Home Assistant cannot hold the voice assistant subscription.
- Make the phrase with any TTS (`say -o wake.aiff "Okay Nabu"`, then `ffmpeg -i wake.aiff -ac 1 -ar 16000
wake16k.wav`) and play it from the host near the device (`PLAY`, default `afplay`). On macOS the terminal needs
audio permission first; before that `afplay` hangs.
- The PE mute switch only mutes samples. To stop microWakeWord, add `mww-buttons.yaml` (template buttons calling
`micro_wake_word.stop` and `start`); `mww.py` checks that no run starts while it is stopped.
- Stale clip check: `stale.py` says a spoken marker word (`marker.aiff`), stops microWakeWord for 3 s, starts it and
says the wake word; `stalean.py` measures loud audio before the phrase in each clip and exits 1 above
`MAX_LOUD_MS` (default 100). The loud level has no default: calibrate `LOUD_LEVEL` on each setup from the phrase
and pre-phrase peaks it prints (a run without it prints them and fails), somewhere between room noise and the
marker's peak. A trial whose phrase peak is under twice `LOUD_LEVEL` fails as too quiet to judge. A steady 1 kHz
beep never reaches the PE stream (the XMOS processing removes it), so the marker has to be speech.
@@ -1,19 +0,0 @@
# sun on_sunrise and on_sunset without waiting for the sun (#21803)
`scripts/sun/sun-common.yaml` (a package) puts the observer on the equator and, once SNTP has synced, searches the
longitudes for one where the sun stands near -5° and rises as the observer moves east. It holds that longitude for
one 60 s elevation poll first: the poll before saw the sun at longitude 0, and the jump could read as a crossing.
Crossings until then are logged as `crossing before the sweep ignored` and not counted. An interval then moves the
longitude by 0.125° every 5 s, which sweeps the elevation from -5° to +6° and back at about 1.5° a minute, reversing
above +6° and below -5°. Five triggers (sunrise at the default, 2° and 4°, sunset at the default and -2°) fire from
the real 60 s elevation poll; each logs the elevation it fired at and counts in `fires`, logged every 30 s.
- The sweep stops after one full pass and logs `sweep done`. `run.sh esp32|esp8266 LABEL` builds, flashes and
captures up to 20 minutes (a pass takes about 17), then `check.py` wants `sweep done` and the counter at 5 with no
trigger firing twice. Run dev and the PR on the same board; two boards can run in parallel.
- At 1.5° a minute a crossing fires up to about 1.7° past its elevation, one poll late at most.
- The seconds past the minute of the fire lines show the poll phase: separate pollers fire at different seconds,
one shared poll fires every trigger in the same second.
- `id(sun_id)` is a pointer in lambdas (`->`). Judge by the `fires` counter: the classic devkit's serial log can
garble single lines.
- Results: https://github.com/esphome/esphome/pull/21803#issuecomment-6490173072
@@ -1,24 +0,0 @@
# CAN (esp32_can) without a transceiver (#21792, #21795)
`scripts/twai_self`: `esp32_can` with `mode: NO_ACK`, TX on GPIO25 and RX on GPIO26. After boot `canself.hpp` enables
the input on GPIO25 and routes it to the controller's receive signal (`esp_rom_gpio_connect_in_signal(25,
TWAI_RX_IDX, false)`), so the controller hears its own transmit pad. Frames go out with `twai_transmit_v2` and
`TWAI_MSG_FLAG_SELF` (the driver handle is reached through explicit template instantiation), so every frame runs
through the normal receive path and `on_frame`.
- `can.yaml` has nine `on_frame` entries (standard and extended ids, masks, remote-only and data-only filters, two
entries with the same filter, an id with bits outside its mask that must never fire) and sends 20 rounds of 7
frames. `run.sh LABEL` writes `out-can<LABEL>.counts` (fires per trigger, id, flags and data); diff dev and the PR.
- Set `rx_queue_len: 32`: with the default 5, a burst of 7 frames loses the last two most of the time, on every
build.
- ESPHome's own `canbus.send` does not set the self flag, so its frames are not received in this setup.
- Results: https://github.com/esphome/esphome/pull/21795#issuecomment-6491777381
## ESP32-C3 and extra frame shapes (#21950)
The C3 works the same way: `variant: esp32c3`, TX GPIO5 and RX GPIO6, `TX_PAD = GPIO_NUM_5` in `canself.hpp`, and
the logger on USB_SERIAL_JTAG. `canx.hpp` adds a classic frame with DLC 12 (`TWAI_MSG_FLAG_DLC_NON_COMP`), the
`send_data` overloads (standard, extended, remote, empty, a 10-byte payload that must be clamped, a vector) and a
`twai_get_status_info_v2` dump before and after (`canx::tx_status(id(can0), "before")`). The `get()` that reads the
private handle is a friend found only by argument-dependent lookup: call `get(canself::Handle{})`, never
`canself::get(...)`.
@@ -1,74 +0,0 @@
# Simulated UART sensors on a classic ESP32 (#21449, #21446)
No sensor needed. `templates/uart_sim/sim.hpp` (included with `esphome: includes:`) has frame builders for wts01,
ds1603l, sm300d2 and ufm01, `sim::loopback(id(uart))` (ESP-IDF `uart_set_loop_back` on the component's own UART),
`sim::send()` that logs the bytes, and `sim::probe`, a SEN0465 responder polled from a 10 ms interval. The run files
`fra.yaml`, `frb.yaml` and `frc.yaml` set the name and include `fr-common.yaml` plus their `fr*-parts.yaml` as
packages; copy them with a different name (`frabase` and so on) for the base build.
- Push-style sensors: put the component on a UART, switch it to loopback in `on_boot`, and inject frames from
template buttons (`fra-parts.yaml`, `frb-parts.yaml`). ufm01 enters its active stream by itself when a 1 s
interval streams frames during its 2 s startup wait.
- Request/response sensors: cross-wire two UARTs through the GPIO matrix (UART1 tx 25 rx 26, UART2 tx 26 rx 25,
`allow_other_uses: true` on all four pins); the second UART runs the simulated device (`frc-parts.yaml`).
A select sets the probe's misbehaviour (tail, FF tail, silent, split, wrong gas).
- Polled readers: run `update()` from a script and log `micros()` around it to measure blocking
(sm300d2 on dev blocks about 104 ms on an empty buffer).
- The logger stays on UART0, so three builds cover five components. Drive with `scripts/uart_sim/frdrive.py HOST
LOG press:NAME sel:NAME=OPT num:NAME=V wait:S @FILE` (`@FILE` reads one op per line), or
`scripts/uart_sim/run.sh NAME TREE SECONDS OPS...` (build and flash from TREE with `esphome run --no-logs`,
capture, drive; `PORT` and `SC` in the environment, `ERASE=1` erases the flash first, `DRIVER` picks another
API driver).
## Particulate sensors: gcja5, pm1006, sds011 (#21939)
`templates/uart_sim/pmsim.hpp` adds frame builders `sim::gcja5`, `sim::pm1006` and `sim::sds011`, each with a bad
checksum or bad end flag. `fp-parts.yaml` puts gcja5 on UART1 (9600 8E1, with a template binary sensor that shows
`status_has_warning()`) and pm1006 on UART2; `fs-parts.yaml` has sds011 alone. Write the run files the same way as
`fra.yaml` (`fp.yaml`, `fs.yaml` with their own name).
- Every button injects one case with its own PM value, so each published state names its case: good, two frames,
bad checksum, end or tail, garbage before a frame, a cut-off frame followed by a good one, a repeated first header
byte, and splits of 300 and 700 ms (either side of the 500 ms gap reset).
- `run.sh NAME TREE 150 @fp-ops.txt` runs the op list from the file; `fs-ops.txt`, `fd-ops.txt` and `fj-ops.txt`
are the other lists.
- The loopback also feeds each component its own writes (pm1006 request, sds011 setup and sleep/work commands),
which must not disturb the next frame.
- The API coalesces two states published in the same loop pass, so "two frames" shows only the second value.
- Found with it: on dev gcja5 published bad and misaligned frames as readings (268435456).
## 4-byte distance sensors: a01nyub, a02yyuw, jsn_sr04t (#21948)
`sim::ds1603l(mm, bad_ck)` builds the same `FF H L sum` frame; `fd-parts.yaml` (a01nyub on UART1, a02yyuw on UART2) and `fj-parts.yaml`
(jsn_sr04t, polled every 15 s), with the same case list as above plus a reading below the minimum distance. With
loopback the jsn_sr04t request byte `55` can land inside a split frame and break it; check the `Request read out`
timestamps before calling a difference between builds.
## LD6002B TinyFrame parser (#19836, #19837)
`templates/uart_sim/ld6002b/`: `ld6sim.hpp` is a fake module on a UART cross-wired to the component's UART (UART1
tx 25 rx 26, UART2 tx 26 rx 25), set up by the shared `ld6-base.yaml` package. It ACKs every command with an empty
frame of the same type and logs the bytes it received (`MOD RX`), so the bytes on the wire can be diffed between
builds. Target reports carry a distinct X per
case, and `T1 X` shows which frames got through.
- `ld6-parser-cases.yaml` (used by `ld6-common.yaml`, which turns the query answers off): good, byte by byte (one
byte per poll, so the component's loop runs in between), garbage before a frame, bad and lost header or data
checksums, an oversized payload, a burst of 20. The script runs by itself from `on_boot`; `ld6p.yaml` is the run file
(copy it with another name for the base build). `run.sh NAME TREE` builds, flashes over serial and captures,
and fails without a `CASE done` line.
- Garbage that contains `01` right before a frame loses that frame on dev and on the PR (a false header, no rescan).
- Full component A/B: `ld6sim.hpp` also answers every query with a fixed report (delay, sensitivity, trigger,
installation, Z range, low power, low power sleep, both area reports, version); `ld6x-common.yaml` has the full
entity set and runs the parser cases too (`ld6x.yaml` is its run file); `ld6drive.py HOST` presses every button,
sets every number and select and toggles every switch over the API. Run it with `ERASE=1 DRIVER=ld6drive.py
scripts/uart_sim/run.sh NAME TREE 100`: switch and select states and the area id are stored preferences, and a previous build's run changes the
next build's boot state.
- `m4-common.yaml` and `m5-common.yaml` run the same fake against `ld6004`: target and area reports, work status and
radar on/off reports, malformed reports, and the point cloud and target display switches across a reboot
(`m5` reboots once and checks the restored switch states). `m4.yaml` and `m5.yaml` are the run files, and like
`ld6p.yaml` each can be copied with another name for the base build. Run m5 with `ERASE=1 run.sh NAME TREE 75`: the boot
counter and switch states are stored preferences that survive a flash, and the second boot's `CASE done` comes
about 49 s after reset. Only the second boot logs `CASE done`, so a skipped reboot fails the run.
See `rs485_frame.md` for the same cross-wired UART trick on an ESP32-C3.
@@ -1,26 +0,0 @@
# udp
## UDP, multicast, sockets (#20556 to #20559, #20585, #20590)
A listener on port 9 needs no privileges on macOS. Test multicast device to device; host to device
multicast never arrives on some access points, and `239.255.x.x` groups are unreliable even to a stock
listener. Broadcast to boards is lossy under power save, unicast is not. Flood at a fixed packet rate
(the host hits `ENOBUFS` unthrottled); 1500 packets per second survived on every board. A forced Wi-Fi
reconnect on the Pico keeps IGMP membership. Set a long loop interval from `wifi.on_connect`
(`App.set_loop_interval(20000)`), not `on_boot`, or Wi-Fi connect crawls. The `logger.log` action
rejects `%.*s`; use a lambda.
## udp.write payload shapes (#21263, ApplyBytes)
`templates/udp-write-dut.yaml` puts every payload shape behind a template button (constant 4 bytes twice, 3, 9, 0,
128, 129 and 600 bytes, a 300 byte lambda, a simple value, a string) plus an `on_receive` that replies with the
received bytes reversed. `scripts/udp/write_cases.sh DEVICE_IP KEY` records the device's datagrams with
`udp_listen.py` on the test host, presses the buttons two seconds apart, sends one unicast datagram for the echo and
compares everything byte for byte with `check.py`; a missing datagram shifts every later one, so read the first
mismatch. Before flashing, check the generated `main.cpp`: on ESP8266 a constant payload is copied out of its
`PROGMEM` table into `uint8_t esphome__bytes[N]` up to the stack limit and into `std::make_unique<uint8_t[]>` beyond,
identical payloads share one table, a lambda is sent from its vector. An empty constant payload is generated as
`send_packet(nullptr, 0)`, and the raw lwIP UDP `sendto` used on ESP8266 rejected a null buffer with `EINVAL`
(`sendto() error 22` in the log, no datagram) until it accepted `nullptr` with a zero length; the old
`TemplatableBytes::visit` had passed a zero length stack buffer instead. Compare sizes against the stacked PR's own
head when the PR is stacked, not against dev. Results: https://github.com/esphome/esphome/pull/21263
@@ -1,52 +0,0 @@
# usb_audio
## USB audio on the Waveshare ESP32-S3-ETH (#21081, #11728)
`templates/usb-audio-waveshare-s3-eth-dut.yaml`: ESP-IDF, PoE, logs over the API on Ethernet (the native USB port is
the host port, so there is no console), `usb_audio` hub, a 48 kHz 16-bit microphone, a 48 kHz 24-bit speaker (many
speakerphones offer only 24-bit; a wrong format logs the device's alternates), buttons for capture start and stop,
a non-blocking beep fed from an 8 ms interval with `play(buf, len, 0)` (a blocking `play()` on the main loop trips
the task watchdog), and a status interval with mic bytes, speaker state and heap. Drive the buttons with
`scripts/api_button.py IP KEY press "Beep"`. Expect 192 kB/s microphone bytes and the FIFO split
RX 80 / NPTX 16 / PTX 104 in the build's `defines.h`; with the balanced split the 294-byte OUT pipe is refused
(`EP MPS (294) exceeds supported limit (128)`). A device whose OUT endpoint is larger than 600 bytes cannot be
claimed on an S3 at all.
## Music Assistant through sendspin
`templates/usb-audio-sendspin-s3-eth-dut.yaml` overlays the template above with the Apollo CAST-1 wiring: resampler
speakers into a mixer whose inputs never time out, `speaker_source` media player with the sendspin source, and
`sendspin: unpaired_access: true`. A `media_player: platform: speaker` is not a media-source consumer and gives
"Player over its buffer", no audio. Music Assistant finds the device by mDNS within 15 s of boot.
Read the result from the device, not only by ear: sendspin's sync task logs `Lost sync (N us off)` (DEBUG, tag
`SsSync`) for every correction over 5 ms, a positive N inserts that much silence, and each one is an audible click.
For the chunk lead histogram, edit the managed library in the build directory,
`.esphome/build/<name>/managed_components/sendspin__sendspin-cpp/src/sync_task.cpp` (an `SS_LOGD` before the
late-chunk skip in `decode_chunk()` printing the chunk's lead against `new_audio_client_playtime`), update only that
file's `size` and sha256 `hash` in the component's `CHECKSUMS.json`, and compile again; deleting `.component_hash` or
recomputing it makes the manager refuse or refetch. Check the edit is in the image with `strings firmware.ota.bin`.
A lead below -5 ms makes the library skip the whole chunk; an I2S speaker keeps it within 0.1 ms of zero, which is
the figure a USB speaker has to match.
Gotchas: wait two minutes after a reboot before the measured stream (safe mode's boot counter write stalls the cores
for about 140 ms once, 60 to 75 s after boot); with the serial console on, a DEBUG log line per report saturates
UART0 and trips the task watchdog, so use `logger: baud_rate: 0` and the API log; two overlapping `esphome logs`
captures double every count; and every audio test must include a pause and resume cycle, since a stream end that
leaves less than one transfer parked in the driver was what hung the speaker after #11728 merged.
## Controls
Apollo CAST PRO-1 (`templates/cast-pro-1-sendspin-control.yaml`): `Core.yaml` next to it is
`Integrations/ESPHome/Core.yaml` from ApolloAutomation/CAST_PRO-1, which also defines the `version` substitution.
Keep its framework log level at ERROR (DEBUG floods driver output and trips the watchdog); the package reboots itself
into Ethernet-only once it sees a link and appends the MAC suffix to the name. `wifi: enable_on_boot: false` keeps
sendspin off Wi-Fi.
Nabu Casa Connect AUX-2 (a pre-production unit): build from `packages/aux-2-pre-prod.yaml` at NabuCasa/aux-2 commit
283f2e64 (dropped in bde41e01), not the public `aux-2.yaml`, whose W5500, codec and I2S pins differ (the public one
reads W5500 chip ID 0x00 and fails the codec's I2C writes). Point its local `external_components` source at
`github://NabuCasa/aux-2@main`. Templates `aux-2-preprod-stock-dut.yaml` (I2S codec) and
`aux-2-preprod-usb-audio-dut.yaml` (the USB speaker as the mixer output via `!extend mixing_speaker`). The console is
the CH343 (1a86:55d3); first flash over it, OTA after. Forcing the Wi-Fi flag off with `restore_value: no` boot-loops
when Ethernet fails, so let the package switch itself.
@@ -1,20 +0,0 @@
# usb_cdc_acm
## usb_cdc_acm on the nRF52840 dongle (#11634)
`templates/usb-cdc-acm-dongle-dut.yaml`: logger on USB_CDC port 0, `usb_cdc_acm` interface 0 disabled,
interface 1 echoing from a 20 ms lambda, 0x01-prefixed commands for burst, stream, flush, peek, line coding
and counters. Build and flash with `dfu: true` through the app port; the dongle then shows three CDC ports:
the board DTS node `cdc_acm_uart` (unused), `cdc_acm_uart0` (log) and `cdc_acm_uart1` (data), in that order.
Capture the log port with `serial_capture.py`, drive the data port with `scripts/usb_cdc_acm/drive.py
DATA_PORT` (11 cases, prints PASS/FAIL and a summary) and grep the log for `Opened`, `Closed`, `buffer full`,
`flush result`, `line coding`. Boot lines are held in the driver's 1 KB ring until the host opens the port, so
a capture started later still shows the first 1 KB of the boot and then a truncated line.
With three CDC instances the Zephyr legacy stack's `CONFIG_USB_MAX_NUM_TRANSFERS=4` starves the last instance
(each instance holds an OUT read and an IN ZLP), so interface 1 shows DTR changes but moves no data.
`scripts/usb_cdc_acm/cdc_probe.hpp` (include it, call `cdc_probe()` from an interval) reads the Zephyr driver
directly to tell a dead endpoint from a component bug. Raising the transfer pool to 8, or disabling the
board's `cdc_acm_uart` node, fixes it. Design limit of the driver: `fifo_fill` holds `tx_ready` until the
write callback and `write_array` drops when the ring is full, so a 64 KiB full-duplex echo loses one 64 byte
tail on every buffer size.
@@ -1,15 +0,0 @@
# sensor and number on_value_range A/B (#21814, #21817, #21818)
`scripts/value_range/value-range-common.yaml` (a package) has one template sensor with seven triggers (constant
bounds, one-sided, a lambda bound on `x`, a bound from another sensor's state that stays NaN until step 22, both
bounds NaN, and an identical twin) and one template number with three triggers. It feeds them 30 values 200 ms apart
(on the bounds, just past them, repeats, NaN, ±inf, a moving bound), then syncs preferences and restarts, then
sends 50, 95 and 50 to check the restored in-range flag. Every fire logs its step and `x`.
- `run.sh bk72xx|esp8266|esp32 LABEL` writes the per-build file with a fresh `tag`, builds, flashes, captures 90 s
(through the restart) and writes `out-rng<kind><LABEL>.seq`; diff dev against each PR head.
- The sequence primes every trigger first (bound 0, value -500, bound NaN): the in-range flags are stored in flash,
so without priming a fresh build starts from whatever the previous run left, and the first fires differ.
- The phase global resets when `tag` changes, so each reflash runs the whole sequence.
- Log line numbers differ between trees; the runner strips them before writing the `.seq` file.
- Results: https://github.com/esphome/esphome/pull/21818#issuecomment-6491846503
@@ -1,15 +0,0 @@
# voice_assistant
## Voice PE late TTS start (#19408)
Only the subscribed client (Home Assistant) may send `VoiceAssistantAnnounceRequest`, so both builds carry
`scripts/voice_announce/slow-announce.yaml`, a template button that calls `id(va).on_announce(msg)` with
`start_conversation = true` and a URL on the host. `drive.py HOST KEY DELAY OUT` serves a FLAC (WAV as `audio/wav`
is rejected by micro_decoder) only after DELAY seconds, presses the button and timestamps the device logs. It
holds the voice assistant subscription throughout, since without a subscriber the device drops the announcement
state at once. It imports `va_common.py` from `scripts/voice_wake_word_audio/`, so keep the two directories side
by side.
`run.sh DEVICE LABEL=CONFIG=TREE...` builds, OTAs and runs both builds twice. The player gives up after 6 header
attempts of 5 s.
The wake word audio flow is in [`speaker.md`](speaker.md).
@@ -1,61 +0,0 @@
# web_server
## State SSE on web_server_idf (#21109) and the HTTPD task stack (#21038)
`templates/web-server-sse-dut.yaml` (ESP32 classic, ESP-IDF, `web_server` version 3) publishes eight sensors every
200 ms (small state events on the 1024 byte stack buffer) and three text sensors whose JSON carries the string twice
(`value` and `state`): 600 chars for about 1.3 kB (the 2048 byte tail), 1800 chars for about 3.7 kB (tail grown to
4096) and 2800 chars for about 5.7 kB, over the 5120 byte JSON room, which must log `State event does not fit`
and never put a truncated frame on the wire. An `interval` lambda logs `uxTaskGetStackHighWaterMark()` of the loop
task (`nullptr`) and of the HTTPD task (`xTaskGetHandle("httpd")`) every 5 s; the ESPHome loop task is `loopTask`
on ESP32. Keep `power_save_mode: none`, and drive the device by address: mDNS names dropped out mid-run once.
`scripts/web_server/sse.py HOST SECONDS [--clients N] [--stall] [--churn CYCLES]` opens raw TCP connections to
`/events`, decodes the chunked body and parses every `state` event as JSON; `--stall` adds a connection with a 2 kB
receive buffer that never reads (the device must log `Closing stuck stream` on ESP-IDF and `Closing stuck
EventSource connection` elsewhere, after the 20 s stall timeout), `--churn` opens and resets a connection CYCLES
times. `sse_cases.sh HOST KEY LABEL CAPTURE` runs the set: 1 client 60 s, 4 clients 60 s, a reader plus a stalled
client 45 s, a reader plus 10 abrupt closes, then two clients with the "Burst" button (50 sensor and 50 text
publishes in one loop pass). Pass: 0 invalid JSON on every client, the oversize sensor dropped with its warning on
every publish, the stalled session closed after about 20 s, no reset. The loop task watermark is a minimum since
boot, so compare the value after the first client, after four clients and after the burst between the builds (the
SSE split in #21109 left 1280 B more on the ESP32 classic).
For the HTTPD task, `web_server: auth: type: digest` (the default `auth` is Basic) and
`scripts/web_server/httpd_cases.sh HOST USER PASS LABEL CAPTURE`: `httpmix.sh` sends a `curl --anyauth` request
mix per round (page, `/sensor/<Name>`, `/text_sensor/<Name>`, `/switch/<Name>`, a `POST` with `Content-Length: 0`
to `/switch/<Name>/toggle`, an unknown path, which the IDF server closes without a response, an unauthenticated
request answered 401, and a 2 s `/events` stream), 20 rounds alone and 12 rounds next to two `ssecurl.sh` SSE
clients. Entity URLs use the entity name, URL encoded, not an object id. The HTTPD watermark follows the deepest
request of the boot; compare after the mix and after the SSE round, with two boots when the numbers are close.
Results: https://github.com/esphome/esphome/pull/21109#issuecomment-6300582328 and
https://github.com/esphome/esphome/pull/21038#issuecomment-6301310182
## Entity icon and device class readback (#21111)
Covers every path that reads an entity's icon or device class: the native API listing, MQTT discovery, the web_server
`/events` listing and REST endpoints, and `dump_config`. `templates/entity-icon-dut.yaml` (ESP8266 board with wifi,
encrypted api, ota, web_server and mqtt against a local broker) carries a sensor with a 63 character icon, one with no
icon or device class, an internal sensor, and binary_sensor, switch, button, text_sensor, number, select, event, cover
and text entities with icons and device classes. The per-run file supplies `name` and `broker_ip` through
substitutions. Flash the PR and base builds under different names, then from the scratch directory:
```sh
scripts/entity_icons/readback.sh DEVICE_IP KEY NAME BROKER_HOST cap-NAME.txt # once per build
scripts/entity_icons/compare.sh ic-base ic-pr # api, web, mqttn, dump all identical
```
`readback.sh` takes about 25 s once the device is on the network: 12 s of `mosquitto_sub` on `homeassistant/#` and
`NAME/#`, the API listing (`api_list.py`, one JSON line per entity with icon, device class, unit, options and event
types) and `web_dump.py` (6 s on `/events`, keeping only the listing rows that carry `domain`, then a GET of each
listed id with `?detail=all` and one retry, because the ESP8266 async server occasionally leaves a request unanswered
within 5 s). The web ids are `domain/Name`, not object ids, and `/event/<name>` has no GET handler (404 on every
build). `mqtt_norm.py` drops the `dev` block (compile time) and the `NAME/debug` topic (heap probe), so a clean run
differs in nothing. `dump_config` prints icons and device classes only for some domains; button, event and
binary_sensor icons never appear there.
Found with this flow on 2026-10-21: since #19577 every ESP8266 `web_server` build that lists a cover, climate, lock,
valve, update, alarm_control_panel or water_heater entity reboots with `Exception (3) LoadStoreErr` in
`json::linked(const char *)` (the ROM `strlen` on a flash address), fixed by #21316. The cover in the template keeps
that path covered; before #21316 is merged, apply its one line change to both trees or the web_server comparison
cannot run.
@@ -1,95 +0,0 @@
# wifi
## `reboot_timeout` with a fallback AP (#9958)
Only one board runs the AP at a time, or stations join the wrong one. AP probe: bogus network,
`ap: {ssid, password, ap_timeout: 5s}`, `reboot_timeout: 60s`, `logger: level: VERBOSE` (ESP32 and
ESP8266 log `AP client connected MAC=` at verbose), `on_boot: logger.log: BOOT`. Station probes:
`reboot_timeout: 0s`, `interval: 150s` running `wifi.disable`, `delay: 20s`, `wifi.enable` (60 s cycles
are too short to cover the due moment). Pass pattern: "Can't connect; rebooting" exactly 60 s after boot
with no station joined, no reboot for minutes while one is, then a reboot within a second of the last
disconnect. The BW15 restarts its AP on every STA retry and cannot be tested this way.
## DHCP lease cache (#17767)
Cycle 20 s awake, `deep_sleep.enter 30s`, wake, 20 s, `App.safe_reboot()`, logging `millis()` at the
`wifi.connected` condition. An RTS hardware reset must fall back to DHCP; a software reboot and a deep
sleep wake must apply the cache. `esphome run --no-logs` silently skipped the upload on one board; use
`upload` then `logs`.
## Wi-Fi Easy Connect (DPP) enrollee (#17934)
Only an Android phone configures: Settings, network details, Add device, Share Wi-Fi (the Wi-Fi list's
QR scanner makes the phone an enrollee). Render the URI with the `qrcode` module and open the PNG.
`esp32: framework: log_level: DEBUG` plus `sdkconfig_options: CONFIG_WPA_DEBUG_PRINT: y` prints the
supplicant state machine.
## WISP bridge with an ethernet upstream (#7147)
`templates/wisp-ethernet-dut.yaml` (ESP32-S3 with a W5500, `wifi: ap:` with `ap_mode: WISP` and no station) and
`templates/wisp-client.yaml` (D1 mini joining the bridge, `http_request` to a web server on the wired LAN and to
`http://example.com/` every 15 s, `time: sntp`). Secrets: `wisp_psk` and `lan_http` (serve a text file on the host
with `python -m http.server 8787 --bind 0.0.0.0` from a scratch directory). Judge by the client's `GET status 200`
lines, the web server log showing the device's ethernet address as the source (NAT), the client's DHCP info (DNS1 is
the LAN resolver) and `SNTP synced`. The device logs `Starting AP` and `DHCP DNS server: <resolver>` on its USB
console; flashing over the air reboots it for repeat boots. Before the AP address and DHCP server moved ahead of the
AP start (the fix in that PR), the first AP start failed on every boot with `esp_netif_dhcps_option failed: 20484`
(DHCP server already started by the AP start event) and `Failed to enable NAT`, and the bridge only came up on the
retry 90 s later; a client that cannot find the SSID for the first minute on an older build is that. With the fix
the bridge is up 6 s after boot. Any change to the ESP-IDF AP start should also rerun the captive portal hammer.
## Reboot against a WPA2/WPA3 PMF access point (#21590)
- AP: `scripts/wpa3_ap/wdap.yaml` on a classic devkit. ESPHome `wifi: ap:` only, then an on_boot lambda switches it
to `WIFI_AUTH_WPA2_WPA3_PSK`, PMF capable, and registers a WIFI_EVENT handler that logs `STA JOIN` and
`STA LEAVE ... reason N` (the include header pulls in `esp_wifi.h`). It disables Wi-Fi after 420 s.
- AP leave reason 3 means the station sent a deauth; reason 2 means the AP found a stale association when the
station came back; several reason 2 before one join are rejected reconnects.
- DUTs (`wdbk.yaml` BK7238, `wdcb.yaml` CB3S, both on `wd-common.yaml`) list the AP at priority 10 and the main
network at 0, and reboot 30 s after joining the AP and 150 s after joining the main network. So they move to the
AP while it is up and fall back to the main network (where they can be flashed over the air) once its window
ends. `run.sh BUILD` flashes the AP, does OTA for the CB3S and a serial flash for the BK7238, then captures one AP
window; `an.py` prints each station's join and leave sequence and fails on a rejected reconnect, an AP that did
not switch to WPA2/WPA3 (`AP CONFIG FAILED`), a DUT missing from the AP events (`DUT_MACS`) or a BK7238 that never
joined the AP.
- Gotchas: the LibreTiny build directory has two `.uf2` files, so flash `firmware.uf2`. The BK7238 serial flash
sometimes fails to link while the chip is in a reboot loop; retry it 3 or 4 times. OTA fails if the DUT reboots
mid-upload; retry.
- Finding: BDK 3.0.78 rejects about 2 reconnects per reboot when the station left without a deauth; BDK 3.0.33
does not.
## WISP and ALWAYS_ON AP rig (#20077)
`scripts/wisp_ap`: the upstream is an ESP32-S3 with Ethernet running a WISP bridge (`wisp-upstream.yaml`) with its AP on
10.40.0.1/24 and web buttons `ap off` and `ap on`. Its subnet must not be 192.168.4.0/24, the DUT AP's default, or
nothing routes. The DUT is a classic devkit (`dut-wisp.yaml` or `dut-always-on.yaml`); the client is a D1 mini on
the DUT's AP (`wispcli.yaml`) logging its DNS server, a name lookup, a GET by name, the AP itself and a LAN file by
IP. `run.sh DUT START SECONDS T:STATE...` switches the upstream AP at the given times and `sum.py` groups the client
results by phase. Capture the D1 mini without `--reset` (a CH340 floods garbage after an RTS reset). Clients keep
the captive portal's DNS answer for its TTL.
## AP restart with WPA3 mixed and LIGHT power save (#21531)
`scripts/wifi_restart`: the WISP upstream (`wisp-upstream-wpa3.yaml`) switched to WPA2/WPA3 mixed by a script that
runs again after every `ap on`, DUTs (`rebk.yaml`, `recb.yaml` on `re-common.yaml`) with a static IP on the bridge's
subnet, a fallback AP, `power_save_mode: LIGHT` and syslog to the host through the NAT. `run.sh BUILD` switches the
AP off and on three times; `an.py` fails on a reboot, a crash or a DUT that is not back on syslog within 120 s of an
AP start. After 19 minutes the DUTs run `wifi.configure` to the main network; that keeps the static IP, so the next
OTA needs the host to have an address on the bridge's subnet as well (an interface alias). The CB3S log is on UART1
(TX1), so its configs need `logger: hardware_uart: UART1`. Runners must `pkill` only their own ports; a global pkill
stops the other runs' captures.
## Channel and network switching with a bench AP (#22142)
`scripts/wifi_channel/`: `bench-ap.yaml` makes an ESP32-S3 an AP-only bench network on a fixed channel (11 by
default; pick one your normal network does not use), and `dut-common.yaml` gives the device under test that AP at
priority 10 plus your normal network, logs every `wifi_info` ssid and channel update (with the channel the component
reports and whether it is connected), and cycles `wifi.disable` and `wifi.enable` every 90 s. `run.sh LABEL` (env
`TREE`, `PORT`, `AP_PORT`, `SC`, `PY`, and `BENCH_CHANNEL` when the AP is not on 11) flashes the device and captures 420 s while it takes the AP down with
`esptool --port <AP port> --after no-reset chip_id` (the board stays in the bootloader) and back with
`--after hard-reset`. The channel sensor must follow every move between the two networks: the run passes when the
connected channel starts and ends on the bench channel with another channel in between.
- Dropping the AP under a connected device gives a `Beacon Timeout` link loss.
- The 90 s interval fires once right after boot.
- A `Disconnected ... Association Leave` right after `Connecting to` is the aborted attempt, not a missed connect.
@@ -1,38 +0,0 @@
# Xiaomi BLE
## Xiaomi, ATC and PVVX parsing without the sensors (#21483)
No Xiaomi devices are needed, and one ESP32 cannot hear its own advertising, so the frames are injected into the
tracker as scan results: everything after the radio runs as normal.
- `scripts/xiaomi_ble/gen.py` writes `frames.hpp` and `expected.json`: plain MiBeacon (0x50), encrypted v5 23 byte
with MAC and 19 byte without, real AES-CCM (`cryptography` AESCCM, tag 4, AAD 0x11, nonce = MAC reversed + pid +
cnt + 3 byte ext counter), ATC (13 byte, big endian) and PVVX (15 byte, little endian) 0x181A frames, a corrupted
tag every other cycle and a counter 0 boot frame. It models the old shared duplicate counter (`base`) and the per
device one (`pr`) and prints the expected publish counts.
- `xbinject.yaml` (ESP-IDF devkit) includes `frames.hpp`; an `interval:` builds a `BLEScanResult` and calls
`global_esp32_ble_tracker->gap_scan_event_handler(r)`. `count.py` counts the `Got Xiaomi` blocks (sensor
publishes are not logged at DEBUG) and compares them with `expected.json`.
- On ESP32 the tracker's own triggers sit in `listeners_`, which runs before `neutral_listeners_` (the
ble_device_base devices), so an `on_ble_service_data_advertise` never sees what a Xiaomi listener did to the
shared data. Check that directly: `xb_rewrite_probe(id(xa))` builds an `ESPBTDevice` with `parse_scan_rst()`,
calls the component's `parse_device()` and logs the service data before and after (`[probe` lines).
- `run.sh inject pr|base` builds, flashes, captures and prints PASS when the counts match that build's model and,
on the PR build, the probe's service data is the same before and after `parse_device()`.
Base dropped a second device's frame with the same counter, the frame after a bad tag and a first frame with
counter 0, and rewrote the shared data in place; the PR fixed all of them.
## Over the air with a second ESP32
- Advertiser: an ESP32-S3 with Ethernet (OTA over Ethernet), `xbadv.yaml` with `adv_frames.hpp` from
`gen.py --ota`. Per frame: stop advertising, `esp_ble_gap_set_rand_addr`, `config_adv_data_raw`, start
non-connectable advertising with `own_addr_type` random, 20 ms interval, 250 ms dwell. Random static addresses
need the top two bits set, so these use C4:C1:38 instead of A4. `esp32_ble:` alone brings up the stack. The
web_server button starts a run: `curl -X POST -d "" http://<advertiser>/button/start/press` (no body gives 411).
Its `failed sends` sensor counts only GAP calls rejected when queued; a frame the controller drops later shows
up as missing publishes in `count.py`, the same as radio loss.
- Receiver: `xbrecv.yaml` on the devkit, passive scan with window = interval = 100 ms. `run.sh ota pr|base` (with
`ADV` set) flashes it, resets it with a capture and presses start 18 s later, so the counter 0 boot frame is the
first one it hears.
- Each frame arrives about 4 times; the counts matched the injection run exactly apart from one radio loss, so the
over the air comparison allows two missing publishes per tag.
@@ -1,10 +0,0 @@
# zephyr
## Zephyr preferences on the nRF52840 dongle (#20810)
`templates/nrf52-preferences-dut.yaml`: logger on USB_CDC at VERBOSE, `flash_write_interval: 5s`, one
`globals` with `restore_value` incremented every 15 s. Give each build its own global id so each first boot
sees a never-saved key (settings survive a reflash). Flow per build: flash through the log port, 40 s capture
of the first boot, then start a second capture and reboot with a 2001 baud touch on the dongle's other CDC
port (the dfu rate callback is global, and the capture holds the log port); `serial_capture.py` reopens the
log port after the USB re-enumeration and gets the buffered boot lines (`load setting`, `Loaded N settings`).
@@ -1,17 +0,0 @@
# zephyr_coredump
## zephyr_coredump crash and decode on nRF52 boards (#13122)
`templates/nrf52-coredump-crash-dut.yaml` (dongle; change `board:` to `adafruit_itsybitsy_nrf52840` for the
ItsyBitsy): `zephyr_coredump:`, `dfu: true`, a `restore_value` global keyed by the `run` substitution
(settings survive a reflash, so bump `run` for every new crash), and an `on_boot` sequence that sets the
flag, yields 3 s so the globals loop saves it (a blocking lambda never gets there and the board crash-loops),
syncs preferences, then writes to 0xDEADBEEF. Flash, keep every port closed for 80 s, then
`scripts/zephyr_coredump/flow.sh LABEL PORT ELF [OUTDIR]` does the three opens (3 s cut, 100 s full print,
20 s reopen) and calls `decode.sh`, which keeps the first complete `#CD:BEGIN#..END#` block, runs Zephyr's
`coredump_serial_log_parser.py` and `coredump_gdbserver.py` from the sdk-nrf ESPHome installed and prints
`bt` and `info threads` with its `arm-zephyr-eabi-gdb`. The ELF is `.pioenvs/<name>/zephyr/zephyr/zephyr.elf`.
Expect about 9 KB dumps, 140 to 150 `#CD:` lines, a 673 ms loop warning for the erase, and `Has stored
dump: 0` on the reopen. Check `compiled on` in every capture: another session flashing the same board
mid-test looks exactly like a failed test otherwise. Boards without a network cannot exercise the API and
MQTT delivery paths of the component; say so in the results.
@@ -1,23 +0,0 @@
# zwave_proxy
## zwave_proxy frame checksums on a live proxy (#20922)
A Z-Wave proxy (ESP32-S3 with the module on `usb_uart`) is a live device: flash it over OTA and read logs
over the API, there is no serial console because the native USB is the host port for the module, so the
boot-time `GET_NETWORK_IDS` exchange is never captured. Home Assistant's Z-Wave JS holds the single API
subscription (it polls `0x3B` every 30 s and resubscribes after every reboot), so do not subscribe from a
script, and keep the device `name:` so it stays on Z-Wave JS; give each build its own scratch directory
instead.
1. `logger: level: VERY_VERBOSE` with `logs: zwave_proxy: VERY_VERBOSE` and DEBUG for the rest: the
`Sending:`, `Received frame:` and `CHECKSUM Received ... Calculated` lines are `ESP_LOGVV`, which needs
the compile-time level.
2. `md5` the two `firmware.ota.bin` files to be sure the A and B builds differ, then `esphome upload
--device <name>.local` and a `timeout 330 esphome logs --device <name>.local` capture started right after
the OTA to catch the resubscribe traffic.
3. `scripts/zwave_proxy/verify_checksums.py <captures>` recomputes the XOR (init 0xFF, LENGTH..payload) over
every logged frame and counts bad checksums and ACK/NAK sent and received; `scripts/zwave_proxy/devinfo.py
<name>.local` prints the firmware version, compile time and the Home ID from the API (a Home ID proves the
device-built `GET_NETWORK_IDS` frame was accepted at boot).
4. Pre-existing: one `zwave_proxy took a long time for an operation` warning on the first frame after the
log client connects, caused by VERY_VERBOSE logging; it appears on dev too.
@@ -1,23 +0,0 @@
# Run artifacts the runners write next to their scripts; none of these patterns match a tracked file.
out-*/
out-*.*
.esphome/
secrets.yaml
__pycache__/
ble_adv_triggers/rxbk72xx*.yaml
ble_adv_triggers/rxesp32*.yaml
ezo_fake_bus/ezo?*.yaml
homeassistant_button/habtn*.yaml
hub_input_sim/hubsim*.yaml
interval/ivl*.yaml
led_driver_sniff/led*.yaml
ota_automations/otaauto*.yaml
output_button/outbtn*.yaml
remote_base/rb*.yaml
sensor_filters/sf?*.yaml
sun/sunesp*.yaml
twai_self/can?*.yaml
uart_button/uartbtn*.yaml
value_range/rng*.yaml
ld2420_sim/ldenergy*.yaml
ld2420_sim/ldsimple*.yaml
@@ -1,211 +0,0 @@
"""Plaintext native API client that lists user actions with their raw argument fields and executes one.
usage: rawactions.py HOST list
rawactions.py HOST exec ACTION key=value [...] (every argument must be given; types from the listing)
Fields of ListEntitiesServicesArgument: 1 name, 2 type, 3 description, 4 example, 5 optional, 6 default_value.
"""
import os
import socket
import struct
import sys
HOST = sys.argv[1]
CMD = sys.argv[2]
ARGS = sys.argv[3:]
TYPE_NAMES = {
0: "bool",
1: "int",
2: "float",
3: "string",
4: "bool[]",
5: "int[]",
6: "float[]",
7: "string[]",
}
def varint(v: int) -> bytes:
out = bytearray()
while True:
b = v & 0x7F
v >>= 7
if v:
out.append(b | 0x80)
else:
out.append(b)
return bytes(out)
def svarint(v: int) -> bytes:
return varint((v << 1) ^ (v >> 63))
def decode_varint(buf: bytes, pos: int) -> tuple[int, int]:
value = shift = 0
while True:
b = buf[pos]
pos += 1
value |= (b & 0x7F) << shift
if not b & 0x80:
return value, pos
shift += 7
def fields(payload: bytes) -> list[tuple[int, int, object]]:
out = []
pos = 0
while pos < len(payload):
key, pos = decode_varint(payload, pos)
fnum, wt = key >> 3, key & 7
if wt == 0:
v, pos = decode_varint(payload, pos)
elif wt == 2:
ln, pos = decode_varint(payload, pos)
v = payload[pos : pos + ln]
pos += ln
elif wt == 5:
v = payload[pos : pos + 4] # fixed32, caller unpacks
pos += 4
else:
raise ValueError(f"wire type {wt}")
out.append((fnum, wt, v))
return out
def frame(mtype: int, payload: bytes) -> bytes:
return b"\x00" + varint(len(payload)) + varint(mtype) + payload
def field_bytes(fnum: int, data: bytes) -> bytes:
return varint((fnum << 3) | 2) + varint(len(data)) + data
def field_varint(fnum: int, v: int) -> bytes:
return varint((fnum << 3) | 0) + varint(v)
def recv_frames(
sock: socket.socket, until: set[int], limit: float = 5.0
) -> list[tuple[int, bytes]]:
sock.settimeout(limit)
buf = bytearray()
frames = []
while True:
try:
chunk = sock.recv(4096)
except TimeoutError:
return frames
if not chunk:
return frames
buf += chunk
while True:
if len(buf) < 3:
break
if buf[0] != 0:
raise ValueError("not plaintext")
try:
ln, p = decode_varint(buf, 1)
mt, p = decode_varint(buf, p)
except IndexError:
break
if len(buf) < p + ln:
break
frames.append((mt, bytes(buf[p : p + ln])))
del buf[: p + ln]
if mt in until:
return frames
def main() -> None:
sock = socket.create_connection((HOST, 6053), timeout=5)
sock.sendall(
frame(
1, field_bytes(1, b"rawactions") + field_varint(2, 1) + field_varint(3, 10)
)
) # HelloRequest
recv_frames(sock, {2})
sock.sendall(frame(3, b"")) # ConnectRequest, no password
recv_frames(sock, {4})
sock.sendall(frame(11, b"")) # ListEntitiesRequest
frames = recv_frames(sock, {19})
services = {}
for mt, payload in frames:
if mt != 41:
continue
name = key = None
args = []
for fnum, _, v in fields(payload):
if fnum == 1:
name = v.decode()
elif fnum == 2:
key = struct.unpack("<I", v)[0]
elif fnum == 3:
a = {
"name": None,
"type": 0,
"description": None,
"example": None,
"optional": None,
"default": None,
}
for af, _, av in fields(v):
if af == 1:
a["name"] = av.decode()
elif af == 2:
a["type"] = av
elif af == 3:
a["description"] = av.decode()
elif af == 4:
a["example"] = av.decode()
elif af == 5:
a["optional"] = bool(av)
elif af == 6:
a["default"] = av.decode()
else:
a[f"field{af}"] = av
args.append(a)
services[name] = (key, args)
if CMD == "list":
for name, (key, args) in services.items():
print(f"action {name} key={key}")
for a in args:
extra = {
k: v
for k, v in a.items()
if k not in ("name", "type") and v is not None
}
print(f" {a['name']}: {TYPE_NAMES.get(a['type'], a['type'])} {extra}")
return
name = ARGS[0]
key, args = services[name]
payload = varint((1 << 3) | 5) + struct.pack("<I", key)
given = dict(kv.split("=", 1) for kv in ARGS[1:])
for a in args:
if a["name"] not in given:
if os.environ.get("ALLOW_MISSING"):
continue # leave the argument out of the request on purpose
sys.exit(f"missing {a['name']}")
raw = given[a["name"]]
t = a["type"]
if t == 0:
av = field_varint(1, 1 if raw.lower() == "true" else 0)
elif t == 1:
av = varint((5 << 3) | 0) + svarint(int(raw)) # sint32 int_
elif t == 2:
av = varint((3 << 3) | 5) + struct.pack("<f", float(raw))
elif t == 3:
av = field_bytes(4, raw.encode())
elif t == 5:
av = b"".join(
varint((7 << 3) | 0) + svarint(int(x)) for x in raw.split(",") if x
) # repeated sint32 int_array
else:
sys.exit(f"type {t} not supported here")
payload += field_bytes(2, av)
sock.sendall(frame(42, payload)) # ExecuteServiceRequest
print(f"sent {name} with {given}")
sock.close()
main()
@@ -1,221 +0,0 @@
"""Pull the store_yaml blob off a device over the native API (plaintext or Noise) and unpack it.
usage: syrecover.py HOST KEY OUTDIR [ORIGDIR] (KEY of - means a plaintext API)
Prints the capability flag, chunk count, advertised and received sizes, encoding, the envelope's files, and
when ORIGDIR is given compares each recovered file with ORIGDIR/<path>.
Run with PYTHONPATH pointing at the esphome tree that has store_yaml (for unpack_envelope). Needs Python 3.14
(compression.zstd) or the zstandard package.
"""
import asyncio
from pathlib import Path
import sys
import time
from aioesphomeapi import api_pb2
from aioesphomeapi._frame_helper.noise import APINoiseFrameHelper
from aioesphomeapi._frame_helper.plain_text import APIPlaintextFrameHelper
from aioesphomeapi.connection import APIConnection, ConnectionParams
from aioesphomeapi.zeroconf import ZeroconfManager
from esphome.components.store_yaml import unpack_envelope
try:
from compression import zstd
except ImportError:
try:
import zstandard as zstd
except ImportError:
sys.exit("needs Python 3.14 (compression.zstd) or the zstandard package")
HOST, KEY, OUT = sys.argv[1], sys.argv[2], Path(sys.argv[3])
ORIG = Path(sys.argv[4]) if len(sys.argv) > 4 else None
HELLO, HELLO_RESP, CONNECT, CONNECT_RESP = 1, 2, 3, 4
DISCONNECT_REQ = 5
FATAL = -1 # queued by report_fatal_error so a waiting expect() stops at once
CAPS_REQ, CAPS_RESP = 149, 150
GET_YAML_REQ, GET_YAML_RESP = 161, 162
def decode_varint(buf: bytes, pos: int) -> tuple[int, int]:
value = shift = 0
while True:
b = buf[pos]
pos += 1
value |= (b & 0x7F) << shift
if not b & 0x80:
return value, pos
shift += 7
def fields(payload: bytes) -> dict[int, list]:
out: dict[int, list] = {}
pos = 0
while pos < len(payload):
key, pos = decode_varint(payload, pos)
fnum, wt = key >> 3, key & 7
if wt == 0:
v, pos = decode_varint(payload, pos)
elif wt == 2:
ln, pos = decode_varint(payload, pos)
v = payload[pos : pos + ln]
pos += ln
elif wt == 5:
v = payload[pos : pos + 4]
pos += 4
else:
raise ValueError(f"wire type {wt}")
out.setdefault(fnum, []).append(v)
return out
async def main() -> None:
loop = asyncio.get_running_loop()
queue: asyncio.Queue[tuple[int, bytes]] = asyncio.Queue()
errors: list[Exception] = []
class Shim(APIConnection):
"""Only the two callbacks the frame helper uses; the real connection logic is bypassed."""
def process_packet(self, msg_type_proto, data) -> None:
queue.put_nowait((msg_type_proto, bytes(data)))
def report_fatal_error(self, err: Exception) -> None:
errors.append(err)
queue.put_nowait((FATAL, b""))
params = ConnectionParams(
addresses=[HOST],
port=6053,
password=None,
client_info="syrecover",
keepalive=15,
zeroconf_manager=ZeroconfManager(),
noise_psk=None if KEY == "-" else KEY,
expected_name=None,
expected_mac=None,
timezone=None,
provide_time=True,
)
shim = Shim(params, None, False, HOST)
if KEY == "-":
helper = APIPlaintextFrameHelper(
connection=shim, client_info="syrecover", log_name=HOST
)
else:
helper = APINoiseFrameHelper(
connection=shim,
noise_psk=KEY,
expected_name=None,
expected_mac=None,
client_info="syrecover",
log_name=HOST,
)
await loop.create_connection(lambda: helper, HOST, 6053)
try:
await asyncio.wait_for(helper.ready_future, 10)
except Exception as exc: # noqa: BLE001
sys.exit(f"handshake failed: {exc!r} {errors}")
print(f"transport {'plaintext' if KEY == '-' else 'noise'}: handshake done")
async def expect(msg_type: int, timeout: float = 10) -> bytes:
while True:
t, d = await asyncio.wait_for(queue.get(), timeout)
if t == msg_type:
return d
if t == FATAL:
sys.exit(
f"transport error while waiting for message {msg_type}: {errors}"
)
if t == DISCONNECT_REQ:
sys.exit(
f"device closed the connection while waiting for message {msg_type}"
)
print(f"skipping message type {t} while waiting for {msg_type}")
hello = api_pb2.HelloRequest(
client_info="syrecover", api_version_major=1, api_version_minor=10
)
helper.write_packets([(HELLO, hello.SerializeToString())], False)
await expect(HELLO_RESP)
# Sent like the client library does; a device without a password never answers it
helper.write_packets(
[(CONNECT, api_pb2.AuthenticationRequest().SerializeToString())], False
)
helper.write_packets(
[(CAPS_REQ, api_pb2.DeviceCapabilitiesRequest().SerializeToString())], False
)
caps = fields(await expect(CAPS_RESP))
supported = None
if 7 in caps:
supported = fields(caps[7][0]).get(1) == [1]
print(f"capabilities: store_yaml field present={7 in caps} supported={supported}")
t0 = time.monotonic()
helper.write_packets([(GET_YAML_REQ, b"")], False)
chunks: list[bytes] = []
total = encoding = None
done = False
while not done:
f = fields(await expect(GET_YAML_RESP, 20))
if 1 in f:
chunks.append(f[1][0])
done = f.get(2) == [1]
if 3 in f:
total = f[3][0]
if 4 in f:
encoding = f[4][0].decode()
dt = time.monotonic() - t0
compressed = b"".join(chunks)
print(f"chunks {len(chunks)} sizes {[len(c) for c in chunks]}")
print(
f"received {len(compressed)} bytes, advertised {total}, encoding {encoding!r}, {dt:.2f} s"
)
# a second request right after: the device must answer again, not stay stuck
helper.write_packets([(GET_YAML_REQ, b"")], False)
again = 0
done = False
while not done:
f = fields(await expect(GET_YAML_RESP, 20))
again += len(f.get(1, [b""])[0])
done = f.get(2) == [1]
print(f"second request: {again} bytes")
helper.close()
if errors:
sys.exit(f"transport errors: {errors}")
if encoding != "zstd":
sys.exit(f"unexpected encoding {encoding!r}, expected 'zstd'")
if total is not None and len(compressed) != total:
sys.exit(f"received {len(compressed)} bytes but the device advertised {total}")
if again != len(compressed):
sys.exit(
f"the second request returned {again} bytes, the first {len(compressed)}"
)
envelope = zstd.decompress(compressed)
files = unpack_envelope(envelope)
print(
f"envelope {len(envelope)} bytes, {len(files)} files, ratio {len(compressed) / len(envelope):.2f}"
)
OUT.mkdir(parents=True, exist_ok=True)
for rel, content in files.items():
target = OUT / rel.replace("../", "up_/")
if not target.resolve().is_relative_to(OUT.resolve()):
print("skipping a path outside the output directory:", rel)
continue
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(content)
note = ""
if ORIG is not None:
orig = (ORIG / rel).resolve()
if orig.exists():
note = (
"IDENTICAL to original"
if orig.read_bytes() == content
else f"DIFFERS from original ({orig.stat().st_size} bytes)"
)
else:
note = "no original"
print(f" {rel}: {len(content)} bytes {note}")
asyncio.run(main())
@@ -1,33 +0,0 @@
"""Press a template button on the test device over the API, or list its buttons.
usage: api_button.py HOST KEY list | press "Button name" [...] (KEY of - means a plaintext API)
"""
import asyncio
import sys
from aioesphomeapi import APIClient, ButtonInfo
HOST, KEY = sys.argv[1], sys.argv[2]
CMD, ARGS = sys.argv[3], sys.argv[4:]
async def main() -> None:
c = APIClient(HOST, 6053, None, noise_psk=None if KEY == "-" else KEY)
await c.connect(login=True)
ents, _ = await c.list_entities_services()
buttons = {e.name: e for e in ents if isinstance(e, ButtonInfo)}
if CMD == "list":
print("\n".join(sorted(buttons)))
else:
for name in ARGS:
if name not in buttons:
sys.exit(f"no button named {name!r}; have {sorted(buttons)}")
c.button_command(buttons[name].key)
print("pressed", name)
await asyncio.sleep(0.3)
await asyncio.sleep(0.5)
await c.disconnect()
asyncio.run(main())
@@ -1,73 +0,0 @@
"""Per wake cycle timings from a serial capture of the deep sleep timing config.
usage: cycles.py CAPTURE [LABEL]
A cycle starts at the boot banner; the numbers are the device's millis() from the timing lines, and the
capture clock gap from the first line of the cycle to the "Dialing" line.
"""
import pathlib
import re
import statistics
import sys
cap = (
pathlib.Path(sys.argv[1]).read_text(encoding="utf-8", errors="replace").splitlines()
)
label = sys.argv[2] if len(sys.argv) > 2 else ""
TS = re.compile(r"^\[(\d\d):(\d\d):(\d\d)(?:\.(\d+))?\]")
def secs(line):
m = TS.match(line)
if not m:
return None
h, mi, s, f = m.groups()
return int(h) * 3600 + int(mi) * 60 + int(s) + (int(f) / 10 ** len(f) if f else 0)
cycles = []
cur = None
for line in cap:
if "rst:0x" in line or (cur is None and "Log initialized" in line):
cur = {"start": secs(line), "reset": line.split("]", 1)[-1].strip()[:60]}
cycles.append(cur)
continue
if cur is None:
continue
if "Dialing" in line:
cur.setdefault("dial_cap", secs(line))
m = re.search(r"wifi connected at (\d+) ms", line)
if m:
cur.setdefault("wifi", int(m.group(1)))
m = re.search(r"client connected at (\d+) ms \((.*?)\)", line)
if m and "client" not in cur:
cur["client"] = int(m.group(1))
cur["who"] = m.group(2)
m = re.search(r"first HA state '(.*?)' at (\d+) ms", line)
if m and "state" not in cur:
cur["state"] = int(m.group(2))
print(f"{label} cycles: {len(cycles)}")
print(
f"{'n':>2} {'wifi ms':>8} {'dial +ms':>9} {'client ms':>10} {'state ms':>9} {'client-wifi':>11} {'state-client':>12} client reset"
)
for i, c in enumerate(cycles, 1):
dial = ""
if c.get("dial_cap") is not None and c.get("start") is not None:
dial = f"{(c['dial_cap'] - c['start']) * 1000:.0f}"
cw = c["client"] - c["wifi"] if "client" in c and "wifi" in c else ""
sc = c["state"] - c["client"] if "state" in c and "client" in c else ""
print(
f"{i:>2} {c.get('wifi', ''):>8} {dial:>9} {c.get('client', ''):>10} {c.get('state', ''):>9} {cw:>11} {sc:>12} {c.get('who', '')} {c.get('reset', '')[:28]}"
)
for c in cycles:
if "client" in c and "wifi" in c:
c["client-wifi"] = c["client"] - c["wifi"]
if "state" in c and "client" in c:
c["state-client"] = c["state"] - c["client"]
for key in ("wifi", "client", "state", "client-wifi", "state-client"):
vals = [c[key] for c in cycles if key in c]
if vals:
print(
f"{key}: n={len(vals)} min={min(vals)} median={statistics.median(vals):.0f} max={max(vals)}"
)
@@ -1,107 +0,0 @@
"""Per Wi-Fi drop timings from a serial capture of the outgoing connection timing config.
usage: wificycles.py CAPTURE [LABEL]
A cycle starts at "wifi cycle disabling"; the numbers are the device's millis() from the timing lines.
"dial" says whether the client that connected first came from the device's own dial ("Dialing" seen after the
reconnect and before the hello) or from an incoming connection ("Accept" seen first).
"""
import pathlib
import re
import statistics
import sys
cap = (
pathlib.Path(sys.argv[1]).read_text(encoding="utf-8", errors="replace").splitlines()
)
label = sys.argv[2] if len(sys.argv) > 2 else ""
TS = re.compile(r"^\[(\d\d):(\d\d):(\d\d)(?:\.(\d+))?\]")
def secs(line):
m = TS.match(line)
if not m:
return None
h, mi, se, f = m.groups()
return int(h) * 3600 + int(mi) * 60 + int(se) + (int(f) / 10 ** len(f) if f else 0)
cycles = []
cur = None
loop_max = []
for line in cap:
m = re.search(r"loop time max (\d+) ms", line)
if m:
loop_max.append(int(m.group(1)))
if "wifi cycle disabling" in line:
cur = {"order": []}
cycles.append(cur)
continue
if cur is None:
continue
m = re.search(r"wifi connected at (\d+) ms", line)
if m and "wifi" not in cur:
cur["wifi"] = int(m.group(1))
cur["wifi_cap"] = secs(line)
if "Dialing" in line:
cur["order"].append("dial")
cur["dials"] = cur.get("dials", 0) + 1
if "dial_cap" not in cur and "wifi_cap" in cur:
cur["dial_cap"] = secs(line)
elif "dial_cap" not in cur and "dial_before_wifi_cap" not in cur:
cur["dial_before_wifi_cap"] = secs(line)
if (
re.search(r"client disconnected at \d+ ms \(\d+\.\d+\.\d+\.\d+\)", line)
and "wifi" in cur
and "client" not in cur
):
cur["dial_closed"] = cur.get("dial_closed", 0) + 1
if "Accept " in line and "wifi" in cur:
cur["order"].append("accept")
m = re.search(r"client connected at (\d+) ms \((.*?)\)", line)
if m and "wifi" in cur and "client" not in cur:
cur["client"] = int(m.group(1))
cur["who"] = m.group(2).split(" ")[0]
cur["via"] = cur["order"][0] if cur["order"] else "?"
m = re.search(r"Connect (failed|timeout)", line)
if m:
cur.setdefault("connect_errors", 0)
cur["connect_errors"] += 1
print(f"{label} cycles: {len(cycles)}")
print(
f"{'n':>2} {'wifi ms':>8} {'dial-wifi cap ms':>16} {'client ms':>10} {'client-wifi':>11} via dials closed client"
)
for i, c in enumerate(cycles, 1):
cw = c["client"] - c["wifi"] if "client" in c and "wifi" in c else ""
c["client-wifi"] = cw
dw = ""
if "wifi_cap" in c and c.get("wifi_cap") is not None:
# the first dial of the cycle, whether it was logged before or after the Wi-Fi line
if c.get("dial_before_wifi_cap") is not None:
dw = f"{(c['dial_before_wifi_cap'] - c['wifi_cap']) * 1000:.0f}"
elif "dial_cap" in c and c["dial_cap"] is not None:
dw = f"{(c['dial_cap'] - c['wifi_cap']) * 1000:.0f}"
c["dial-wifi"] = dw
print(
f"{i:>2} {c.get('wifi', ''):>8} {dw:>16} {c.get('client', ''):>10} {cw:>11} {c.get('via', ''):7s} {c.get('dials', 0):>5} {c.get('dial_closed', 0):>6} {c.get('who', '')}"
)
for via in ("dial", "accept"):
vals = [
c["client-wifi"]
for c in cycles
if c.get("via") == via and c["client-wifi"] != ""
]
if vals:
print(
f"client-wifi via {via}: n={len(vals)} min={min(vals)} median={statistics.median(vals):.0f} max={max(vals)}"
)
dws = [float(c["dial-wifi"]) for c in cycles if c.get("dial-wifi") not in ("", None)]
if dws:
print(
f"dial after wifi connected (capture clock): n={len(dws)} min={min(dws):.0f} median={statistics.median(dws):.0f} max={max(dws):.0f}"
)
if loop_max:
print(
f"loop time max per 5 s: n={len(loop_max)} min={min(loop_max)} median={statistics.median(loop_max):.0f} max={max(loop_max)}"
)
@@ -1,60 +0,0 @@
"""Shared helpers for the API drivers: connect with retries, and the text of an API log line.
Import it with this directory on sys.path (the drivers add their parent directory, runners set PYTHONPATH).
"""
import asyncio
import contextlib
import os
import re
import sys
from aioesphomeapi import (
APIClient,
EncryptionPlaintextAPIError,
InvalidAuthAPIError,
InvalidEncryptionKeyAPIError,
RequiresEncryptionAPIError,
)
ANSI = re.compile(r"\x1b\[[0-9;]*[A-Za-z]")
# a wrong key or a plaintext/Noise mismatch does not go away with a retry
FATAL = (
EncryptionPlaintextAPIError,
InvalidAuthAPIError,
InvalidEncryptionKeyAPIError,
RequiresEncryptionAPIError,
)
async def connect(host: str, tries: int = 30, timeout: float = 10) -> APIClient:
"""Connect and log in, retrying once a second; exits after TRIES failures with the last error.
API_KEY in the env selects Noise; unset, empty or - is plaintext.
"""
key = os.environ.get("API_KEY")
last: BaseException | None = None
for _ in range(tries):
c = APIClient(
host, 6053, None, noise_psk=None if key in (None, "", "-") else key
)
try:
await asyncio.wait_for(c.connect(login=True), timeout)
except FATAL as e:
sys.exit(f"no API connection to {host}: {type(e).__name__}: {e}")
except Exception as e: # noqa: BLE001
last = e
# release the half-open socket so retries do not use up the device's API slots
with contextlib.suppress(Exception):
await c.disconnect(force=True)
await asyncio.sleep(1)
else:
return c
sys.exit(
f"no API connection to {host} after {tries} tries: {type(last).__name__}: {last}"
)
def log_text(msg) -> str:
"""The message of a subscribe_logs callback as text, without ANSI colour codes."""
return ANSI.sub("", msg.message.decode(errors="replace"))
@@ -1,348 +0,0 @@
# Automation code generation trace: every step logs a marker "M <case> <values>". A package: the per-run file from
# run.sh supplies the board, Wi-Fi and name. drive.py records the markers over the API.
logger:
level: DEBUG
api:
reboot_timeout: 0s
ota:
- platform: esphome
globals:
- {id: g_a, type: int, initial_value: "0"}
- {id: g_b, type: int, initial_value: "0"}
- {id: g_tick, type: int, initial_value: "0"}
- {id: g_ticking, type: bool, initial_value: "false"}
- {id: g_par, type: int, initial_value: "0"}
- {id: g_par3, type: int, initial_value: "0"}
- {id: g_par4, type: int, initial_value: "0"}
interval:
- interval: 100ms
then:
- if:
condition:
lambda: return id(g_ticking);
then:
- lambda: id(g_tick)++;
number:
- platform: template
id: num
name: Num
optimistic: true
min_value: 0
max_value: 100
step: 1
on_value:
- logger.log: {format: "M num_on_value %.0f", args: [x]}
- if:
condition:
lambda: return x > 50;
then:
- logger.log: {format: "M num_high %.0f", args: [x]}
else:
- logger.log: {format: "M num_low %.0f", args: [x]}
switch:
- platform: template
id: sw
name: Sw
optimistic: true
on_turn_on:
- logger.log: "M sw_on"
- globals.set: {id: g_b, value: !lambda "return id(g_b) + 1;"}
- logger.log: {format: "M sw_on_b %d", args: [id(g_b)]}
on_turn_off:
- logger.log: "M sw_off"
select:
- platform: template
id: sel
name: Sel
optimistic: true
options: [a, b, c]
initial_option: a
on_value:
- logger.log: {format: "M sel_on_value %s idx %d", args: [x.c_str(), (int) i]}
sensor:
- platform: template
id: sens
name: Sens
update_interval: never
on_value_range:
- above: 50
then:
- logger.log: {format: "M sens_above %.0f", args: [x]}
- below: 10
then:
- logger.log: {format: "M sens_below %.0f", args: [x]}
alarm_control_panel:
- platform: template
id: acp
name: Acp
codes: ["1234"]
requires_code_to_arm: false
arming_away_time: 0s
on_armed_away:
- logger.log: "M acp_armed_away"
on_disarmed:
- logger.log: "M acp_disarmed"
on_state:
- logger.log: "M acp_state"
button:
- platform: template
name: Run All
on_press:
- logger.log: "M press_run_all"
- script.execute: master
- platform: template
name: Chain Button
on_press:
- logger.log: "M cb_1"
- lambda: id(g_a) = 7;
- globals.set: {id: g_b, value: "3"}
- logger.log: {format: "M cb_2 %d %d", args: [id(g_a), id(g_b)]}
- switch.toggle: sw
- logger.log: "M cb_3"
script:
- id: s_single
mode: single
parameters: {x: int}
then:
- logger.log: {format: "M single_start %d", args: [x]}
- delay: 150ms
- logger.log: {format: "M single_end %d", args: [x]}
- id: s_restart
mode: restart
parameters: {x: int, s: string}
then:
- logger.log: {format: "M restart_start %d %s", args: [x, s.c_str()]}
- delay: 150ms
- logger.log: {format: "M restart_end %d %s", args: [x, s.c_str()]}
- id: s_queued
mode: queued
max_runs: 5
parameters: {x: int}
then:
- logger.log: {format: "M queued_start %d", args: [x]}
- delay: 60ms
- logger.log: {format: "M queued_end %d", args: [x]}
- id: s_parallel
mode: parallel
parameters: {x: int}
then:
- logger.log: {format: "M parallel_start %d", args: [x]}
- delay: !lambda "return 50 + x * 30;"
- logger.log: {format: "M parallel_end %d", args: [x]}
- id: s_selfstop
mode: single
then:
- logger.log: "M selfstop_1"
- lambda: id(g_a) = 100;
- script.stop: s_selfstop
- logger.log: "M selfstop_SHOULD_NOT_RUN"
- lambda: id(g_a) = 200;
- id: s_par_self
mode: parallel
max_runs: 2
then:
- lambda: id(g_par)++;
- logger.log: {format: "M parself_run %d running=%d", args: [id(g_par), (int) id(s_par_self).is_running()]}
- if:
condition:
lambda: return id(g_par) < 4;
then:
- script.execute: s_par_self
- delay: 200ms
- id: s_par3
mode: parallel
max_runs: 3
then:
- lambda: id(g_par3)++;
- logger.log: {format: "M par3_run %d", args: [id(g_par3)]}
- if:
condition:
lambda: return id(g_par3) < 8;
then:
- script.execute: s_par3
- delay: 200ms
- id: s_par4
mode: parallel
max_runs: 4
then:
- lambda: id(g_par4)++;
- logger.log: {format: "M par4_run %d", args: [id(g_par4)]}
- if:
condition:
lambda: return id(g_par4) < 8;
then:
- script.execute: s_par4
- delay: 200ms
- id: master
mode: single
then:
- logger.log: "M c1_chain_start"
- lambda: id(g_a) = 1;
- globals.set: {id: g_b, value: "2"}
- logger.log: {format: "M c1_vals %d %d", args: [id(g_a), id(g_b)]}
- switch.turn_on: sw
- number.set: {id: num, value: 42}
- select.set: {id: sel, option: b}
- lambda: |-
int local = id(g_a) + id(g_b);
if (local > 0) { ESP_LOGI("main", "M c1_lambda_local %d", local); return; }
ESP_LOGI("main", "M c1_lambda_NOT_REACHED");
- logger.log: "M c1_after_return"
- logger.log: "M c2_delay_chain_start"
- delay: 50ms
- logger.log: "M c2_after_delay"
- lambda: id(g_a) = 5;
- delay: 0ms
- logger.log: {format: "M c2_end %d", args: [id(g_a)]}
- logger.log: "M c3_if_start"
- repeat:
count: 4
then:
- if:
condition:
and:
- lambda: return iteration % 2 == 0;
- not:
lambda: return iteration == 2;
then:
- logger.log: {format: "M c3_even_not2 %d", args: [iteration]}
else:
- if:
condition:
or:
- lambda: return iteration == 1;
- xor:
- lambda: return iteration == 2;
- lambda: return false;
then:
- logger.log: {format: "M c3_or_xor %d", args: [iteration]}
else:
- logger.log: {format: "M c3_else %d", args: [iteration]}
- logger.log: "M c4_choose_start"
- repeat:
count: 3
then:
- choose:
- if:
lambda: return iteration == 0;
then:
- logger.log: {format: "M c4_choice0 %d", args: [iteration]}
- if:
lambda: return iteration == 1;
then:
- logger.log: {format: "M c4_choice1 %d", args: [iteration]}
- else:
- logger.log: {format: "M c4_default %d", args: [iteration]}
- logger.log: "M c5_while_start"
- globals.set: {id: g_a, value: "0"}
- while:
condition:
lambda: return id(g_a) < 4;
then:
- logger.log: {format: "M c5_while %d", args: [id(g_a)]}
- lambda: id(g_a)++;
- logger.log: {format: "M c5_while_done %d", args: [id(g_a)]}
- globals.set: {id: g_a, value: "0"}
- while:
condition:
lambda: return id(g_a) < 3;
then:
- logger.log: {format: "M c5_while_delay %d", args: [id(g_a)]}
- delay: 20ms
- lambda: id(g_a)++;
- logger.log: {format: "M c5_while_delay_done %d", args: [id(g_a)]}
- logger.log: "M c6_repeat_start"
- repeat:
count: 2
then:
- lambda: id(g_b) = iteration;
- repeat:
count: 3
then:
- logger.log: {format: "M c6_nested outer=%d inner=%d", args: [id(g_b), iteration]}
- repeat:
count: !lambda "return id(g_b) + 2;"
then:
- logger.log: {format: "M c6_dyn %d", args: [iteration]}
- delay: 10ms
- logger.log: "M c7_wait_until_start"
- lambda: |-
id(g_tick) = 0;
id(g_ticking) = true;
- wait_until:
condition:
lambda: return id(g_tick) >= 3;
timeout: 2s
- logger.log: {format: "M c7_waited %d", args: [(int) (id(g_tick) >= 3)]}
- wait_until:
condition:
for:
time: 300ms
condition:
lambda: return id(g_tick) >= 3;
timeout: 3s
- lambda: id(g_ticking) = false;
- logger.log: "M c7_for_done"
- logger.log: "M c8_scripts_start"
- script.execute: {id: s_single, x: 1}
- script.execute: {id: s_single, x: 2}
- script.wait: s_single
- script.execute: {id: s_restart, x: 1, s: one}
- delay: 40ms
- script.execute: {id: s_restart, x: 2, s: two}
- script.wait: s_restart
- script.execute: {id: s_queued, x: 1}
- script.execute: {id: s_queued, x: 2}
- script.execute: {id: s_queued, x: 3}
- script.wait: s_queued
- script.execute: {id: s_parallel, x: 2}
- script.execute: {id: s_parallel, x: 1}
- script.wait: s_parallel
- logger.log: "M c9_selfstop_start"
- script.execute: s_selfstop
- script.wait: s_selfstop
- logger.log: {format: "M c9_selfstop_g_a %d", args: [id(g_a)]}
- logger.log: "M c10_sensor_start"
- sensor.template.publish: {id: sens, state: 60}
- sensor.template.publish: {id: sens, state: 30}
- sensor.template.publish: {id: sens, state: 5}
- logger.log: "M c11_acp_start"
- alarm_control_panel.arm_away: acp
- delay: 100ms
- alarm_control_panel.disarm: {id: acp, code: "1234"}
- delay: 100ms
- logger.log: "M c12_parself_start"
- globals.set: {id: g_par, value: "0"}
- script.execute: s_par_self
- delay: 800ms
- logger.log: {format: "M c12_parself_total %d", args: [id(g_par)]}
- logger.log: "M c13_parmax_start"
- globals.set: {id: g_par3, value: "0"}
- script.execute: s_par3
- delay: 800ms
- logger.log: {format: "M c13_par3_total %d", args: [id(g_par3)]}
- globals.set: {id: g_par4, value: "0"}
- script.execute: s_par4
- delay: 800ms
- logger.log: {format: "M c13_par4_total %d", args: [id(g_par4)]}
- switch.turn_off: sw
- logger.log: "M done"
esphome:
on_boot:
priority: -100
then:
- logger.log: "M boot"
- delay: 8s
- script.execute: master
@@ -1,72 +0,0 @@
"""Record every 'M ...' marker from the device log while driving the automation trace config.
usage: drive.py HOST OUT env: API_KEY (unset for a plaintext API)
Order: wait for the boot run's 'M done', press Run All and wait for 'M done' again, press Chain Button twice, set Num
70 then 20, toggle Sw on and off, select c then a. Writes one marker per line to OUT (timestamps dropped). Exits 1
when the Run All pass never reached 'M done'.
"""
import asyncio
import pathlib
import re
import sys
from aioesphomeapi import LogLevel
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
from apiconn import connect, log_text # noqa: E402
HOST, OUT = sys.argv[1], sys.argv[2]
marks: list[str] = []
done = asyncio.Event()
async def main() -> bool:
cli = await connect(HOST)
def on_log(m) -> None:
if mm := re.search(r"\]: (M .*)$", log_text(m)):
marks.append(mm.group(1).strip())
if mm.group(1).strip() == "M done":
done.set()
cli.subscribe_logs(on_log, log_level=LogLevel.LOG_LEVEL_DEBUG)
infos, _ = await cli.list_entities_services()
by = {i.name: i for i in infos}
try:
await asyncio.wait_for(done.wait(), 40)
except TimeoutError:
marks.append("DRIVER boot run not seen")
marks.append("DRIVER press Run All")
done.clear()
cli.button_command(by["Run All"].key)
ok = True
try:
await asyncio.wait_for(done.wait(), 40)
except TimeoutError:
marks.append("DRIVER run all timed out")
ok = False
steps = (
("cb1", lambda: cli.button_command(by["Chain Button"].key)),
("cb2", lambda: cli.button_command(by["Chain Button"].key)),
("num70", lambda: cli.number_command(by["Num"].key, 70.0)),
("num20", lambda: cli.number_command(by["Num"].key, 20.0)),
("swon", lambda: cli.switch_command(by["Sw"].key, True)),
("swoff", lambda: cli.switch_command(by["Sw"].key, False)),
("selc", lambda: cli.select_command(by["Sel"].key, "c")),
("sela", lambda: cli.select_command(by["Sel"].key, "a")),
)
for label, send in steps:
marks.append(f"DRIVER {label}")
send()
await asyncio.sleep(0.8)
await asyncio.sleep(1)
await cli.disconnect()
return ok
OK = asyncio.run(main())
pathlib.Path(OUT).write_text("\n".join(marks) + "\n", encoding="utf-8")
print(f"{len(marks)} lines")
sys.exit(0 if OK else 1)
@@ -1,40 +0,0 @@
#!/bin/bash
# run.sh LABEL: build the automation trace config as at<LABEL> from TREE, flash it over PORT, read the device address
# from the serial log, record the marker trace with drive.py and keep the part from "DRIVER press Run All" on in
# out-at<LABEL>.trace. Diff the .trace files of dev and the PR; the boot run is partly missed while the API connects.
# Run it from a scratch copy of this directory with a secrets.yaml (wifi_ssid, wifi_password).
# env: TREE (esphome checkout), PORT (serial port), SC (path to serial_capture.py), PY (checkout python),
# BOARD (esp32 board, default esp32dev), VARIANT (default esp32), API_KEY (only if you add api encryption)
R=$(cd "$(dirname "$0")" && pwd); L=${1:?label}; T=${TREE:?set TREE}; P=${PORT:?set PORT}
PY=${PY:-$T/venv/bin/python}; SC=${SC:?set SC}; NAME=at$L; OUT=$R/out-$NAME; rm -rf "$OUT"; mkdir -p "$OUT"
cat > "$R/$NAME.yaml" <<YAML
esphome:
name: $NAME
esp32:
board: ${BOARD:-esp32dev}
variant: ${VARIANT:-esp32}
framework:
type: esp-idf
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
packages:
trace: !include automation-trace-common.yaml
YAML
pkill -f "[s]erial_capture.py $P"
(cd "$T" && $PY -m esphome run --no-logs "$R/$NAME.yaml" --device "$P" > "$OUT/upload.log" 2>&1) || { echo "build or upload failed"; exit 1; }
grep -a -E '^(RAM|Flash):' "$OUT/upload.log"
$PY "$SC" "$P" 120 "$OUT/serial.txt" --reset > /dev/null 2>&1 &
CAP=$!; trap 'kill $CAP 2>/dev/null' EXIT
H=; for _ in $(seq 60); do
H=$(grep -a -o -E 'IP Address: [0-9.]+' "$OUT/serial.txt" 2>/dev/null | tail -1 | awk '{print $3}'); [ -n "$H" ] && break; sleep 1
done
[ -n "$H" ] || { echo "FAIL: no IP address in the serial log"; exit 1; }
PYTHONPATH=$(dirname "$SC") $PY "$R/drive.py" "$H" "$OUT/markers.txt"; RC=$?
sed -n '/^DRIVER press Run All/,$p' "$OUT/markers.txt" > "$R/out-$NAME.trace"
CR=$(grep -a -c -E 'Guru|abort\(\)|Backtrace|task_wdt' "$OUT/serial.txt")
echo "$NAME: $(wc -l < "$R/out-$NAME.trace") trace lines, crashes $CR"
[ "$CR" = 0 ] || { echo "FAIL: a crash or watchdog in the serial log"; exit 1; }
[ "$RC" = 0 ] || { echo "FAIL: Run All never reached M done"; exit 1; }
grep -q -E "SHOULD_NOT_RUN|NOT_REACHED" "$R/out-$NAME.trace" && { echo "FAIL: a step that must be skipped ran"; exit 1; }
echo PASS
@@ -1,64 +0,0 @@
"""Compare two full flash dumps of a BK72xx board per partition of its LibreTiny board layout.
usage: partdiff.py BEFORE.bin AFTER.bin LAYOUT.json
LAYOUT.json is a board base file from the LibreTiny platform (for example boards/_base/beken-72xx.json); its
"flash" map ("name": "0xSTART+0xLENGTH") names the partitions. Prints the 4 KB sectors that changed in each one,
plus any changed sector outside the map (a WARN, to check by hand). Exits 1 when the bootloader, calibration or
userdata partition changed.
"""
import json
import pathlib
import sys
before, after = (pathlib.Path(p).read_bytes() for p in sys.argv[1:3])
if len(before) != len(after):
sys.exit(
f"dump sizes differ: {len(before)} and {len(after)} bytes; compare two whole chip reads"
)
parts = []
for name, span in json.loads(pathlib.Path(sys.argv[3]).read_text(encoding="utf-8"))[
"flash"
].items():
start, length = (int(x, 16) for x in span.split("+"))
parts.append((start, start + length, name))
parts.sort()
PROTECTED = ("bootloader", "calibration", "userdata")
if missing := [n for n in PROTECTED if n not in {name for _, _, name in parts}]:
sys.exit(
f"the layout has no {', '.join(missing)} partition; use the Beken board base file"
)
if (end := max(e for _, e, _ in parts)) > len(before):
sys.exit(
f"the layout reaches {end:#x} but the dumps are {len(before):#x} bytes; read the whole chip"
)
SECTOR = 0x1000
covered = set()
protected = []
for start, end, name in parts:
changed = [
a
for a in range(start, end, SECTOR)
if before[a : a + SECTOR] != after[a : a + SECTOR]
]
covered.update(range(start, end, SECTOR))
if changed and name in PROTECTED:
protected.append(name)
listed = " ".join(hex(a) for a in changed[:4]) if 0 < len(changed) <= 4 else ""
print(
f"{name:12} {len(changed):4} of {(end - start) // SECTOR:4} sectors changed {listed}"
)
other = [
a
for a in range(0, len(before), SECTOR)
if a not in covered and before[a : a + SECTOR] != after[a : a + SECTOR]
]
print(
f"{'unmapped':12} {len(other):4} sectors changed {' '.join(hex(a) for a in other[:8])}"
)
if other:
print(
"WARN: sectors outside the layout changed; check what they held in the backup"
)
if protected:
sys.exit(f"FAIL: {', '.join(protected)} changed")
@@ -1,19 +0,0 @@
#!/bin/bash
# usage: readback.sh TAG [START LENGTH] read flash from a BK72xx over its adapter into TAG.bin (whole chip by default)
# env: PORT (adapter), FAMILY (ltchiptool family, default beken-7238), FLASH_BK (path to flash_bk72xx.py),
# LT (LibreTiny penv python, default ~/.platformio/penv/.libretiny/bin/python), SIZE (whole chip bytes, default
# 2097152). A whole 2 MB chip takes about 190 s. The read must come back at the expected size.
T=${1:?tag}; P=${PORT:?set PORT}; FB=${FLASH_BK:?set FLASH_BK}; LT=${LT:-$HOME/.platformio/penv/.libretiny/bin/python}
ARGS=(); [ -n "$2" ] && ARGS=(-s "$2" -l "${3:?length}")
WANT=$(( ${3:-${SIZE:-2097152}} ))
: > "$T.log"
ok=
for i in 1 2 3; do
echo "### try $i" >> "$T.log"
rm -f "$T.bin"
timeout 900 "$LT" "$FB" flash read -d "$P" "${ARGS[@]}" "${FAMILY:-beken-7238}" "$T.bin" >> "$T.log" 2>&1 &&
[ "$(wc -c < "$T.bin" | tr -d ' ')" = "$WANT" ] && ok=1 && break
sleep 3
done
[ -n "$ok" ] || { echo "FAIL: read $T (expected $WANT bytes, see $T.log)"; exit 1; }
shasum -a 256 "$T.bin"
@@ -1,61 +0,0 @@
#pragma once
// Rotating non-connectable advertisements with known service and manufacturer data (random static addresses).
#include <esp_gap_ble_api.h>
#include <cstring>
#include "esphome/core/log.h"
namespace af {
struct Frame {
uint8_t last; // address C4:C1:38:00:00:<last>
uint8_t len;
uint8_t adv[31];
};
// AD structures after the flags. 0x16 = service data 16-bit, 0x20 = 32-bit, 0x21 = 128-bit, 0xFF = manufacturer.
static const Frame FRAMES[] = {
// 21: service 181C AA01 + manufacturer 02E5 BB01
{0x21, 12, {5, 0x16, 0x1C, 0x18, 0xAA, 0x01, 5, 0xFF, 0xE5, 0x02, 0xBB, 0x01}},
// 22: service 32-bit 12345678 AA02
{0x22, 8, {7, 0x20, 0x78, 0x56, 0x34, 0x12, 0xAA, 0x02}},
// 23: service 128-bit 12345678-9ABC-DEF0-1122-334455667788 (wire order) AA03
{0x23, 20, {19, 0x21, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, 0xAA, 0x03}},
// 24: manufacturer 181C BB04 (same id as the service UUID of 21, other data kind)
{0x24, 6, {5, 0xFF, 0x1C, 0x18, 0xBB, 0x04}},
// 25: service 181C AA05 then a second 181C entry AA06 (only the first may fire)
{0x25, 12, {5, 0x16, 0x1C, 0x18, 0xAA, 0x05, 5, 0x16, 0x1C, 0x18, 0xAA, 0x06}},
// 26: the 128-bit UUID in printed byte order AA07 (must not match)
{0x26, 20, {19, 0x21, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xAA, 0x07}},
};
static constexpr int COUNT = sizeof(FRAMES) / sizeof(FRAMES[0]);
static uint32_t failed = 0;
static uint32_t sent = 0;
inline void send(int i) {
const Frame &f = FRAMES[i];
uint8_t adv[31];
uint8_t n = 0;
adv[n++] = 2;
adv[n++] = 0x01;
adv[n++] = 0x06;
memcpy(adv + n, f.adv, f.len);
n += f.len;
esp_ble_gap_stop_advertising();
uint8_t addr[6] = {0xC4, 0xC1, 0x38, 0x00, 0x00, f.last};
esp_err_t e1 = esp_ble_gap_set_rand_addr(addr);
esp_err_t e2 = esp_ble_gap_config_adv_data_raw(adv, n);
esp_ble_adv_params_t p{};
p.adv_int_min = 0x20; // 20 ms
p.adv_int_max = 0x20;
p.adv_type = ADV_TYPE_NONCONN_IND;
p.own_addr_type = BLE_ADDR_TYPE_RANDOM;
p.channel_map = ADV_CHNL_ALL;
p.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
esp_err_t e3 = esp_ble_gap_start_advertising(&p);
sent++;
if (e1 != ESP_OK || e2 != ESP_OK || e3 != ESP_OK) {
failed++;
ESP_LOGW("af", "frame %d failed: %d %d %d", i, e1, e2, e3);
}
}
} // namespace af
@@ -1,41 +0,0 @@
# Advertiser for the service and manufacturer data trigger test: any ESP32 with BLE. Every 250 ms it switches to
# the next of six raw non-connectable advertisements in adv_frames.hpp (addresses C4:C1:38:00:00:21 to 26).
esphome:
name: advtrig
includes:
- adv_frames.hpp
esp32:
board: esp32-s3-devkitc-1
variant: esp32s3
framework:
type: esp-idf
logger:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
reboot_timeout: 0s
ota:
- platform: esphome
esp32_ble:
globals:
- id: idx
type: int
initial_value: "0"
interval:
- interval: 250ms
then:
- lambda: |-
af::send(id(idx));
id(idx) = (id(idx) + 1) % af::COUNT;
- interval: 30s
then:
- lambda: ESP_LOGI("af", "sent %u, failed %u", (unsigned) af::sent, (unsigned) af::failed);
@@ -1,72 +0,0 @@
"""check.py CAPTURE [--zero-mac any|filter]: judge the last count report of a receiver capture.
Expected per trigger (see triggers.yaml): T1 AA01+AA05, T2 AA01, T3 nothing, T4 AA02, T5 AA03, T6 BB01, T7 BB04,
T8 the same count as T2, T9 (mac 00:00:00:00:00:00) AA01+AA05 with --zero-mac any or nothing with filter,
T10 AA03, T11 nothing. "other" on a trigger without a MAC filter is another device in range and is only reported.
Prints PASS or FAIL with the reason and exits 0 or 1.
"""
import argparse
import pathlib
import re
import sys
NO_MAC = {1, 7, 10}
def main() -> int:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("capture")
parser.add_argument("--zero-mac", choices=["any", "filter"], default="filter")
args = parser.parse_args()
zero = args.zero_mac
text = pathlib.Path(args.capture).read_text(encoding="utf-8", errors="replace")
rows: dict[int, dict[str, int]] = {}
for m in re.finditer(r"count T(\d+):([^\n]*)", text):
counts = dict(re.findall(r"(AA\d\d|BB\d\d|other)=(\d+)", m.group(2)))
rows[int(m.group(1))] = {k: int(v) for k, v in counts.items()}
if len(rows) != 11:
print(
f"FAIL: found {len(rows)} trigger rows, want 11 (no report in the capture?)"
)
return 1
want = {
1: {"AA01", "AA05"},
2: {"AA01"},
3: set(),
4: {"AA02"},
5: {"AA03"},
6: {"BB01"},
7: {"BB04"},
8: {"AA01"},
9: {"AA01", "AA05"} if zero == "any" else set(),
10: {"AA03"},
11: set(),
}
# With --zero-mac any, the all-zero MAC means no filter, so T9 also hears other devices
no_mac = NO_MAC | {9} if zero == "any" else NO_MAC
bad = []
for t, keys in want.items():
got = {k for k in rows[t] if k != "other"}
if got != keys:
bad.append(f"T{t} fired on {sorted(got)}, want {sorted(keys)}")
if rows[t].get("other") and t not in no_mac:
bad.append(
f"T{t} has other={rows[t]['other']} although it filters on a MAC"
)
if keys and min(rows[t].get(k, 0) for k in keys) < 10:
bad.append(
f"T{t} has fewer than 10 hits on one of {sorted(keys)}: {rows[t]}"
)
if rows[8] != rows[2]:
bad.append(f"T8 {rows[8]} differs from T2 {rows[2]} (same filter)")
for t in sorted(rows):
print(f"T{t}: {rows[t]}")
print("FAIL: " + "; ".join(bad) if bad else "PASS")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())
@@ -1,21 +0,0 @@
#!/bin/bash
# run.sh esp32|bk72xx LABEL: build rx-<kind>.yaml as rx<kind><LABEL> from TREE, flash it, capture 150 s, run check.py.
# The advertiser (advtrig.yaml) must already be running on a second ESP32 in range.
# env: TREE (esphome checkout to build from), PORT (receiver serial port), SC (path to serial_capture.py),
# PY (checkout python), BOARD (bk72xx board, default xh-wb3s), BKPY + BKFLASH (python and flash_bk72xx.py for
# bk72xx), ZERO_MAC (any or filter, what mac_address 00:00:00:00:00:00 should do on this build; default filter)
R=$(cd "$(dirname "$0")" && pwd); K=${1:?esp32 or bk72xx}; L=${2:?label}; T=${TREE:?set TREE}; P=${PORT:?set PORT}
PY=${PY:-$T/venv/bin/python}; SC=${SC:?set SC}; NAME=rx$K$L; OUT=$R/out-$NAME; rm -rf "$OUT"; mkdir -p "$OUT"
sed -e "s/\${name}/$NAME/" -e "s/\${board}/${BOARD:-xh-wb3s}/" "$R/rx-$K.yaml" > "$R/$NAME.yaml"
pkill -f "[s]erial_capture.py $P"
if [ "$K" = esp32 ]; then
(cd "$T" && $PY -m esphome run --no-logs "$R/$NAME.yaml" --device "$P" > "$OUT/upload.log" 2>&1) || { echo "build or upload failed"; exit 1; }
$PY "$SC" "$P" 150 "$OUT/serial.txt" --reset > /dev/null 2>&1
else
(cd "$T" && $PY -m esphome compile "$R/$NAME.yaml" > "$OUT/compile.log" 2>&1) || { echo "build failed"; exit 1; }
${BKPY:?set BKPY} "${BKFLASH:?set BKFLASH}" flash write -d "$P" "$R/.esphome/build/$NAME/.pioenvs/$NAME/firmware.uf2" > "$OUT/flash.log" 2>&1 || { echo "flash failed"; exit 1; }
$PY "$SC" "$P" 150 "$OUT/serial.txt" > /dev/null 2>&1
fi
[ -s "$OUT/serial.txt" ] || { echo "serial capture got nothing"; exit 1; }
grep -a "adverts" "$OUT/serial.txt" | tail -1
$PY "$R/check.py" "$OUT/serial.txt" --zero-mac "${ZERO_MAC:-filter}"
@@ -1,39 +0,0 @@
# Receiver on a BK72xx board (bk72xx_ble_tracker). substitutions: name, board
# Wi-Fi must be configured: without it the BK7238 tracker logs "Scan started" and never receives anything.
esphome:
name: ${name}
includes:
- rx.hpp
bk72xx:
board: ${board}
logger:
hardware_uart: UART1
level: DEBUG
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
bk72xx_ble:
enable_on_boot: true
bk72xx_ble_tracker:
scan_parameters:
interval: 100ms
window: 30ms
continuous: true
<<: !include triggers.yaml
on_ble_advertise:
- then:
- lambda: |-
rx::all++;
if ((x.address_uint64() >> 8) == 0xC4C1380000ULL) rx::ours++;
interval:
- interval: 20s
then:
- lambda: |-
rx::report("count");
ESP_LOGI("rx", "adverts %u, from the advertiser %u", (unsigned) rx::all, (unsigned) rx::ours);
@@ -1,32 +0,0 @@
# Receiver on a classic ESP32 (esp32_ble_tracker). substitutions: name
esphome:
name: ${name}
includes:
- rx.hpp
esp32:
board: esp32dev
framework:
type: esp-idf
logger:
level: DEBUG
esp32_ble_tracker:
scan_parameters:
interval: 100ms
window: 100ms
active: false
<<: !include triggers.yaml
on_ble_advertise:
- then:
- lambda: |-
rx::all++;
if ((x.address_uint64() >> 8) == 0xC4C1380000ULL) rx::ours++;
interval:
- interval: 20s
then:
- lambda: |-
rx::report("count");
ESP_LOGI("rx", "adverts %u, from the advertiser %u", (unsigned) rx::all, (unsigned) rx::ours);
@@ -1,37 +0,0 @@
#pragma once
// Per trigger counts of the received payloads: AAnn (service data) and BBnn (manufacturer data) from the advertiser,
// anything else counted as "other".
#include <cstdint>
#include <cstdio>
#include <vector>
#include "esphome/core/log.h"
namespace rx {
static constexpr int TRIGGERS = 12;
static uint32_t cnt[TRIGGERS][16];
static uint32_t other[TRIGGERS];
static uint32_t all, ours;
inline void hit(int t, const std::vector<uint8_t> &x) {
if (x.size() == 2 && (x[0] == 0xAA || x[0] == 0xBB) && x[1] >= 1 && x[1] <= 7) {
cnt[t][(x[0] == 0xBB ? 8 : 0) + x[1]]++;
} else {
other[t]++;
}
}
inline void report(const char *label) {
for (int t = 1; t < TRIGGERS; t++) {
char buf[160];
int n = snprintf(buf, sizeof(buf), "T%d:", t);
for (int k = 0; k < 16; k++) {
if (cnt[t][k])
n += snprintf(buf + n, sizeof(buf) - n, " %s%02u=%u", k >= 8 ? "BB" : "AA", (unsigned) (k & 7),
(unsigned) cnt[t][k]);
}
if (other[t])
n += snprintf(buf + n, sizeof(buf) - n, " other=%u", (unsigned) other[t]);
ESP_LOGI("rx", "%s %s", label, buf);
}
}
} // namespace rx
@@ -1,44 +0,0 @@
# Shared trigger block, included under the tracker key.
on_ble_service_data_advertise:
- service_uuid: 181C
then:
- lambda: rx::hit(1, x);
- mac_address: C4:C1:38:00:00:21
service_uuid: 181C
then:
- lambda: rx::hit(2, x);
- mac_address: C4:C1:38:00:00:22
service_uuid: 181C
then:
- lambda: rx::hit(3, x);
- mac_address: C4:C1:38:00:00:22
service_uuid: "12345678"
then:
- lambda: rx::hit(4, x);
- mac_address: C4:C1:38:00:00:23
service_uuid: 12345678-9ABC-DEF0-1122-334455667788
then:
- lambda: rx::hit(5, x);
- mac_address: C4:C1:38:00:00:21
service_uuid: 181C
then:
- lambda: rx::hit(8, x);
- mac_address: 00:00:00:00:00:00
service_uuid: 181C
then:
- lambda: rx::hit(9, x);
- service_uuid: 12345678-9ABC-DEF0-1122-334455667788
then:
- lambda: rx::hit(10, x);
on_ble_manufacturer_data_advertise:
- mac_address: C4:C1:38:00:00:21
manufacturer_id: 02E5
then:
- lambda: rx::hit(6, x);
- manufacturer_id: 181C
then:
- lambda: rx::hit(7, x);
- mac_address: C4:C1:38:00:00:22
manufacturer_id: 02E5
then:
- lambda: rx::hit(11, x);
@@ -1,39 +0,0 @@
# Add to a copy of a bluetooth_proxy config: packages: {cp_inject: !include cp-inject.yaml}
esphome:
includes:
- cp_inject.hpp
logger:
level: VERBOSE
logs:
esp32_ble_tracker: DEBUG
bluetooth_proxy: DEBUG
bluetooth_connection: DEBUG
api: DEBUG
api.service: DEBUG
api.connection: DEBUG
api.socket: DEBUG
scheduler: DEBUG
sensor: DEBUG
component: DEBUG
button:
- platform: template
name: Inject conn param events
# The handlers push into a queue that takes one writer only, the Bluetooth task. Stop the scan (and keep the
# proxy free of real connections) so nothing else writes while the button does.
on_press:
- esp32_ble_tracker.stop_scan:
- wait_until:
condition:
lambda: return !esp32_ble_tracker::global_esp32_ble_tracker->scan_running();
timeout: 5s
- delay: 1s
- lambda: |-
if (esp32_ble_tracker::global_esp32_ble_tracker->scan_running()) {
ESP_LOGE("cpinject", "scan still running after 5 s, nothing injected");
return;
}
cpinject::run();
- esp32_ble_tracker.start_scan:
continuous: true
Loaded 100 of 8144 files, more files were not shown because too many files have changed in this diff. Show more