Compare commits

...

748 Commits

Author SHA1 Message Date
Jonathan Swoboda
9ab2a573ab Merge pull request #17093 from esphome/bump-2026.6.2
2026.6.2
2026-06-20 14:17:55 -04:00
Jonathan Swoboda
99d1c4eb69 Bump version to 2026.6.2 2026-06-20 13:33:41 -04:00
esphome[bot]
b079be756f Bump bundled esphome-device-builder to 1.0.12 (#17091) 2026-06-20 13:33:41 -04:00
J. Nick Koston
039a1f063e [ha-addon] Expose the device-builder public port only when port 6052 is mapped (#17076) 2026-06-20 13:33:41 -04:00
esphome[bot]
2354165e41 Bump bundled esphome-device-builder to 1.0.11 (#17081) 2026-06-20 13:33:41 -04:00
Jonathan Swoboda
f5697b0ae5 [packet_transport] Mark encryption key as cv.sensitive (#17066) 2026-06-20 13:33:41 -04:00
Jonathan Swoboda
fe794a26e8 [fastled_base] Fix RMT5 intr_priority conflict (#17072) 2026-06-20 13:33:41 -04:00
Jonathan Swoboda
8d77051b9a [espidf] Resolve IDF tools path to avoid unnormalized path warning (#17055) 2026-06-20 13:33:41 -04:00
Jesse Hills
9534ab2a19 Merge pull request #17052 from esphome/bump-2026.6.1
2026.6.1
2026-06-19 11:35:03 +12:00
Jesse Hills
1b1c8d767d Bump version to 2026.6.1 2026-06-19 10:06:13 +12:00
esphome[bot]
e3d68deef9 Bump bundled esphome-device-builder to 1.0.10 (#17051) 2026-06-19 10:06:13 +12:00
J. Nick Koston
20cd6a1771 [logger] Hold recursion guard while draining the task log buffer (#17044) 2026-06-19 10:06:13 +12:00
Jonathan Swoboda
d27229a1c7 [esp32] Don't overwrite PlatformIO's factory.bin (#17042) 2026-06-19 10:06:13 +12:00
Jonathan Swoboda
129aebe8f4 [esp32] Support esphome idedata with the native ESP-IDF toolchain (#17040) 2026-06-19 10:06:13 +12:00
Jonathan Swoboda
a84ad7b1f8 [uptime] Revert timestamp sensor device_class to timestamp (#17037) 2026-06-19 10:06:13 +12:00
Jonathan Swoboda
86096b96f5 [build] Skip target-platform deps when populating host unit-test config (#17039) 2026-06-19 10:06:13 +12:00
J. Nick Koston
ac5a28301a [core] Honor transferred address cache in has_resolvable_address (#17025)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-19 10:06:13 +12:00
Jesse Hills
e2157a3d26 Merge pull request #17022 from esphome/bump-2026.6.0
2026.6.0
2026-06-18 12:59:50 +12:00
esphome[bot]
d934fb3910 Bump bundled esphome-device-builder to 1.0.9 (#17021)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-18 10:46:22 +12:00
esphome[bot]
c4076ec8a9 Bump bundled esphome-device-builder to 1.0.8 (#17020) 2026-06-18 10:46:12 +12:00
esphome[bot]
9ac22f9244 Bump bundled esphome-device-builder to 1.0.7 (#17018) 2026-06-18 10:46:06 +12:00
Jesse Hills
9e7b3e0330 Bump version to 2026.6.0 2026-06-18 10:18:37 +12:00
Jesse Hills
2abe272867 Merge pull request #17017 from esphome/bump-2026.6.0b4
2026.6.0b4
2026-06-18 10:08:15 +12:00
Jesse Hills
db6b9166f4 Bump version to 2026.6.0b4 2026-06-18 08:20:15 +12:00
esphome[bot]
7ab95ddcb1 Bump bundled esphome-device-builder to 1.0.6 (#17016) 2026-06-18 08:20:02 +12:00
esphome[bot]
cdd2bfbc60 Bump bundled esphome-device-builder to 1.0.4 (#17013) 2026-06-18 08:19:05 +12:00
esphome[bot]
41f7f8cccb Bump bundled esphome-device-builder to 1.0.3 (#17005) 2026-06-18 08:19:05 +12:00
Jonathan Swoboda
045de436ba [ota] Scale ESP-IDF OTA erase watchdog to image size (#16998) 2026-06-18 08:19:05 +12:00
Jonathan Swoboda
24e276c3f9 [esp32_hosted] Bump esp_hosted to 2.12.9 (#16999) 2026-06-18 08:18:25 +12:00
Jesse Hills
9e768bb510 Merge pull request #16997 from esphome/bump-2026.6.0b3
2026.6.0b3
2026-06-16 23:52:22 +12:00
Jesse Hills
53fd99578a Bump version to 2026.6.0b3 2026-06-16 23:02:55 +12:00
Jesse Hills
310baab524 [docker] Bundle device-builder 1.0.1, make HA add-on builder-only (#16989)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-16 23:02:55 +12:00
Jesse Hills
0422b581cb [core] Stop parent git repos from breaking ESP-IDF/PlatformIO builds (#16994) 2026-06-16 23:02:55 +12:00
Jesse Hills
0ce89c17ab [ci] Push branch-tagged docker images to ghcr.io for local testing (#16992) 2026-06-16 23:02:55 +12:00
Jesse Hills
66be793cd8 [docker] Remove alpine base, build only on debian (#16991) 2026-06-16 23:02:54 +12:00
Jonathan Swoboda
1d38498ca7 [openthread] Fix InstanceLock releasing the lock twice on try_acquire (#16980) 2026-06-16 23:02:54 +12:00
Kevin Ahrendt
aef9b5b72f [audio] Bump microMP3 to v0.2.3 (#16977) 2026-06-16 23:02:54 +12:00
J. Nick Koston
9bf35ab8fb [core] Attribute "took a long time" blocking warning to the owning script (#16768) 2026-06-16 23:02:54 +12:00
Clyde Stubbs
33ace9d698 [mipi_dsi] Add SWRESET command to M5Stack Tab5-V2 init sequence (#16975) 2026-06-16 23:02:54 +12:00
Jesse Hills
32ab3abd7c [psram] Make schema extractable with per-variant options (#16949)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-16 23:02:54 +12:00
Jesse Hills
94b248527d Merge pull request #16948 from esphome/bump-2026.6.0b2
2026.6.0b2
2026-06-15 12:05:19 +12:00
Jesse Hills
a46aa594b3 Bump version to 2026.6.0b2 2026-06-15 11:04:46 +12:00
Jonathan Swoboda
99425e3a97 [esp32] Add flash_mode and flash_frequency config options (#16920)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2026-06-15 11:04:46 +12:00
Jonathan Swoboda
f83e3ad6a6 [core] Support platformio_options on the native ESP-IDF toolchain (#16917) 2026-06-15 11:04:46 +12:00
Jonathan Swoboda
c768e2eabc [esp32] Fix idedata generation failing on unset ESPHOME_ARDUINO (#16925) 2026-06-15 11:04:46 +12:00
Clyde Stubbs
9ffd350095 [mipi_spi] Implement automatic mapping of offsets (#16722)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-15 11:04:46 +12:00
Clyde Stubbs
26ccaf70db [lvgl] Fix schema extraction (#16895)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:04:46 +12:00
Tobiasz Jakubowski
20925b3220 [spi] Skip logging on begin_transaction() of an auto-releasing write-only SPI device (#16921)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-06-15 11:04:46 +12:00
J. Nick Koston
83504d2de2 [esp8266] Decode crash handler PC and backtrace in logs (#16911) 2026-06-15 11:04:46 +12:00
Jesse Hills
acbb662316 Merge pull request #16912 from esphome/bump-2026.6.0b1
2026.6.0b1
2026-06-11 16:06:59 +12:00
Jesse Hills
abf6212a5a [tests] Mock target branch in memory-impact exclusion test (#16913) 2026-06-11 14:05:10 +12:00
Jesse Hills
4dbc5ce920 Bump version to 2026.6.0b1 2026-06-11 12:41:19 +12:00
Keith Burzinski
92c82f3d25 [improv_serial] Report stopped state when Wi-Fi is disabled (#16904)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 10:26:50 +12:00
Kevin Ahrendt
77009cfafe [resampler] Allow resampler to passthrough bits per sample instead of converting (#16892)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-11 10:21:04 +12:00
dependabot[bot]
cd7e54dbf2 Bump cryptography from 48.0.0 to 48.0.1 (#16909)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 16:32:17 -04:00
Jonathan Swoboda
29a79b1373 [core] Make set_cpp_standard work on the native IDF toolchain (#16907) 2026-06-11 07:25:03 +12:00
Clyde Stubbs
dafc3560dd [tests] Isolate ESPHOME_LOG_STATES in main logs-states tests (#16905)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 07:44:58 -04:00
Clyde Stubbs
a25ac28ae5 [lsm6ds] Add motion platform for STMicro LSM6DS IMU (#16232)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2026-06-10 01:22:44 +00:00
Jonathan Swoboda
6809af3de0 [espidf] Warn when the install path is too long for Windows MAX_PATH (#16896) 2026-06-10 13:12:28 +12:00
Jonathan Swoboda
e16a877745 [platformio] De-duplicate non-ESP32 lib_deps into common:idf-component-libs (#16893) 2026-06-10 13:11:11 +12:00
Jonathan Swoboda
4963ddcb95 [espidf] Fix idedata generation on Windows (#16894) 2026-06-10 13:09:50 +12:00
Clyde Stubbs
4f62bb7171 [bmi270] Support Bosch BMI270 IMU (#16202)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-10 11:04:28 +10:00
Ricky Tsai
eb6d6eac7d [xdb401] XDB401 Pressure Sensor (#15108)
Co-authored-by: Ricky Tsai <ricky@rtnztech.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-06-09 19:58:02 -04:00
dependabot[bot]
7533835e04 Bump py7zr from 0.22.0 to 1.1.0 (#16901)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 16:03:31 -04:00
Oliver Kleinecke
2310b9e3fe [usb_uart] Add Prolific PL2303 USB-serial driver (#16885) 2026-06-10 04:27:37 +10:00
Tomáš Lohynský
8206df6e4e [dlms_meter] dlms_parser library (#15458)
Co-authored-by: PolarGoose <35307286+PolarGoose@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-09 08:57:13 -04:00
tomaszduda23
5faed9d5f5 [nrf52] native build - download toolchain and sdk in venv (#16388)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <swoboda1337@users.noreply.github.com>
2026-06-09 07:04:51 -04:00
PolarGoose
25d656d468 [dsmr] Update dsmr_parser library to 1.9.0 (#16881) 2026-06-09 07:04:10 -04:00
Remco van Essen
cdc63f0fed [pcm5122] Add PCM5122 audio DAC component (#15709)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: kbx81 <kbx81x@gmail.com>
2026-06-09 01:33:15 -05:00
Clyde Stubbs
ddd21ba442 [mipi_spi] add WAVESHARE-ESP32-S3-TOUCH-AMOLED-2.16 (#16887) 2026-06-09 13:06:13 +10:00
Jonathan Swoboda
a32817207c [ade7880] Fix reverse active energy reading from reserved register (#16822) 2026-06-08 20:30:03 -04:00
Jonathan Swoboda
6e01f3fccd [heatpumpir] Bump tonia/HeatpumpIR to 1.0.42 (#16880) 2026-06-08 20:29:35 -04:00
dependabot[bot]
e0072ef4c5 Bump tornado from 6.5.6 to 6.5.7 (#16883)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-08 19:22:48 -05:00
dependabot[bot]
b21a69f07a Bump codecov/codecov-action from 6.0.1 to 7.0.0 (#16884)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-09 08:08:39 +12:00
J. Nick Koston
36e043debb [tests] Fail component test merge on conflicting duplicate IDs (#16849) 2026-06-08 12:49:25 -05:00
Kevin P. Fleming
54c73bf1bc [ade7880][airthings_wave_base] Remove kpfleming from CODEOWNERS (#16858) 2026-06-08 09:04:09 -04:00
J. Nick Koston
cbc3770b11 Include model-driven display schemas in the language schema dump (#16872) 2026-06-07 17:30:43 -05:00
Jonathan Swoboda
64fc09646c [esp32] Fix clang-tidy on ESP-IDF 6 (#16850) 2026-06-06 20:00:42 -04:00
Jonathan Swoboda
8400bab926 [esp32] Make no-default-board variant test explicit about platformio toolchain (#16847) 2026-06-06 19:58:25 -04:00
Clyde Stubbs
745db9f705 [motion] Implement hub component for IMUs (#16226)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-06 18:10:08 +10:00
Jonathan Swoboda
6996b7ed1c [ci] Add ESP32 Variants clang-tidy run (S3/P4/C6) (#16825) 2026-06-05 22:03:08 -04:00
Jonathan Swoboda
8aa4157574 [fastled_base] Use FastLED IDF component on ESP32 (#16804) 2026-06-05 21:01:29 -04:00
J. Nick Koston
2a4913713a Revert "[tests] Fail component test merge on conflicting duplicate IDs" (#16848) 2026-06-05 19:37:19 -05:00
J. Nick Koston
8f8a70b2be Exit nginx bypass placeholder cleanly on SIGTERM (#16845) 2026-06-05 17:58:50 -05:00
J. Nick Koston
70d9ab25f3 [tests] Fail component test merge on conflicting duplicate IDs (#16795) 2026-06-05 17:57:42 -05:00
Jonathan Swoboda
f18cf954ba [improv_serial] Fix build on ESP32-C5/P4 and simplify variant guards (#16833) 2026-06-05 17:30:26 -05:00
Jonathan Swoboda
85fd83288d [esp32_camera] Bump esp32-camera to 2.1.7 (#16846) 2026-06-05 17:29:33 -05:00
Clyde Stubbs
93334d4e60 [scripts] Fix build_language_schema (#16816)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-05 21:44:31 +00:00
i-am-no-magic
913b9f5ca4 [tuya] Fixed hysteresis bug for Tuya climate (#16832)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-06-05 17:37:40 -04:00
Kevin Ahrendt
b63e327ae3 [audio] Deprecate unused scale_audio_samples helper (#16831) 2026-06-05 17:22:03 -04:00
Jonathan Swoboda
77f644f576 [ci] Share a cached native ESP-IDF install across clang-tidy and build jobs (#16841) 2026-06-05 16:42:51 -04:00
Ross Tyler
4cb6f2c046 [qmp6988] fix publishing bogus zero values on i2c error (#16840) 2026-06-05 14:35:33 -04:00
Ross Tyler
2ab4399ae5 [qmp6988] fix false report of software reset error (#16843) 2026-06-05 14:31:17 -04:00
Jonathan Swoboda
aa11ddb333 [zigbee][openthread][esp32_hosted] Fix clang-tidy findings (#16838) 2026-06-05 14:22:55 -04:00
Jonathan Swoboda
2b581ecd3c [esp32] Bump platform to 55.03.39, Arduino to 3.3.9 (#16803) 2026-06-05 14:22:20 -04:00
Jonathan Swoboda
42cf421f5c [usb_uart] Fix clang-tidy findings (#16835) 2026-06-05 12:03:22 -04:00
Jonathan Swoboda
351b986896 [ci] Make ESP32 IDF the comprehensive clang-tidy pass (#16823)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-06-05 12:01:53 -04:00
Jonathan Swoboda
b0e1b94c45 [mipi_dsi][mipi_rgb][st7701s][rpi_dpi_rgb] Fix clang-tidy findings (#16837) 2026-06-05 11:56:48 -04:00
Jonathan Swoboda
80c84d6665 [usb_host][usb_cdc_acm][tinyusb] Fix clang-tidy findings (#16836) 2026-06-05 11:55:39 -04:00
J. Nick Koston
61bb1805b1 [api] Fix nullptr deref when client teardown reenters state dispatch (#16834) 2026-06-05 10:47:32 -05:00
Jesse Hills
cbd3aaa1e0 [ci] Add codecov.yml to enforce 100% patch coverage on PRs (#16827) 2026-06-05 19:40:18 +12:00
Oliver Kleinecke
e209a3fa91 [usb_uart] Add FTDI FT23XX USB UART driver (#14587)
Co-authored-by: Oliver Kleinecke <kleinecke.oliver@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2026-06-05 13:57:05 +10:00
Jesse Hills
d72f119dd2 Merge branch 'release' into dev 2026-06-05 14:31:50 +12:00
Jesse Hills
0cd3734148 Merge pull request #16817 from esphome/bump-2026.5.3
2026.5.3
2026-06-05 14:31:04 +12:00
Jonathan Swoboda
ea3ac1ee96 [audio] Bump esp-audio-libs to v3.2.1 (#16818) 2026-06-04 20:02:22 -04:00
Jesse Hills
7f3feec3a3 Bump version to 2026.5.3 2026-06-05 11:11:36 +12:00
Jonathan Swoboda
bcf5606b31 [esp32_ble_server] Fix duplicate Device Information Service with string UUIDs (#16784) 2026-06-05 11:11:36 +12:00
Jonathan Swoboda
5662e1b7cd [rp2040] Fix lwipopts template load on Windows extended-length paths (#16783) 2026-06-05 11:11:35 +12:00
Jonathan Swoboda
375ecdfb2c [esp32][core] Restore ESP-IDF version on logs/upload fast path and clean build on framework change (#16770) 2026-06-05 11:11:25 +12:00
Jonathan Swoboda
a5b4a7cd51 [remote_base] Fix RC5 decoding at either receive polarity (#16767) 2026-06-05 11:07:33 +12:00
dependabot[bot]
772cae445f Bump github/codeql-action from 4.36.1 to 4.36.2 (#16808)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 17:30:29 -05:00
dependabot[bot]
ef64d27ed4 Bump ruff from 0.15.15 to 0.15.16 (#16807)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 17:30:18 -05:00
Jesse Hills
a8032054ea [light] Pass light reference into lambda light effect (#16815) 2026-06-05 10:28:50 +12:00
J. Nick Koston
9fbd4c38ae [i2s_audio] Move test bus into a shared package and give fixtures unique ids (#16793) 2026-06-04 17:28:32 -05:00
Jonathan Swoboda
82efa45187 [multiple] Avoid float-to-double promotion in math calls (#16812) 2026-06-04 18:16:18 -04:00
Jonathan Swoboda
d2c388f893 [ota][logger][esp32][internal_temperature] Fix clang-tidy findings surfaced by RISC-V analysis (#16811) 2026-06-04 18:01:00 -04:00
Jonathan Swoboda
5288767abf [clang-tidy] Add --exclude-grep to skip files by content (#16813) 2026-06-04 17:58:22 -04:00
Jonathan Swoboda
e2459a3923 [clang-tidy] Support RISC-V targets natively (#16809) 2026-06-04 17:57:56 -04:00
Kevin Ahrendt
419bde18b0 [audio] Bump esp-audio-libs to v3.2.0 (#16806) 2026-06-04 16:24:47 -04:00
Jonathan Swoboda
148a5ba68e [esp32] Run clang-tidy via the native ESP-IDF toolchain (#16748) 2026-06-04 11:47:42 -04:00
J. Nick Koston
c765e22622 [ci] Exclude device-builder slow e2e tests from downstream CI (#16801) 2026-06-04 10:39:54 -05:00
Clyde Stubbs
1734dc85d2 [const][animation][dfplayer] Extract CONF_LOOP to const (#16797) 2026-06-04 07:42:01 -04:00
Jonathan Swoboda
891ec33c94 [esp32] Deduplicate PlatformIO library conversion by resolving the batch together (#16756) 2026-06-04 07:39:17 -04:00
Jonathan Swoboda
ffaa31febc [clang-tidy] Hash idf_component.yml and trigger hash hook on more inputs (#16753)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-06-03 23:48:34 -04:00
Jonathan Swoboda
53d685f242 [mixer] Give mixer test its own speaker id to avoid CI grouping collision (#16792) 2026-06-03 23:37:29 -04:00
J. Nick Koston
3e562b9267 [ci] Fix memory impact build selecting unbuildable platform (#16788) 2026-06-03 22:30:36 -05:00
dependabot[bot]
d47f6b896e Bump astral-sh/setup-uv from 8.1.0 to 8.2.0 in /.github/actions/restore-python (#16790)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 22:06:59 -05:00
dependabot[bot]
a02b9c3796 Bump astral-sh/setup-uv from 8.1.0 to 8.2.0 (#16791)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 22:06:45 -05:00
Jesse Hills
93f25258ee [config] Add --no-defaults flag to config command (#16718) 2026-06-04 14:08:36 +12:00
Jonathan Swoboda
0d7d091e71 [esp32_ble_server] Fix duplicate Device Information Service with string UUIDs (#16784) 2026-06-04 09:46:17 +12:00
Jonathan Swoboda
0fcfd1e3d6 [rp2040] Fix lwipopts template load on Windows extended-length paths (#16783) 2026-06-04 09:46:08 +12:00
Jonathan Swoboda
74a1ff9fc7 [esp32][core] Restore ESP-IDF version on logs/upload fast path and clean build on framework change (#16770) 2026-06-04 09:46:01 +12:00
Jonathan Swoboda
78d8a93fff [remote_base] Fix RC5 decoding at either receive polarity (#16767) 2026-06-04 09:45:56 +12:00
Jon Little
92819d8658 [logger] Fix USB JTAG VFS symbols linked when logging is disabled (#15721)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-03 16:54:34 -04:00
Clyde Stubbs
7b8cbe2de1 [sdl] Add option to choose display screen (#16363) 2026-06-03 14:18:16 -04:00
Leonardo Rivera
3b0f669f47 [gree] Fix HEAT_COOL advertised when supports_heat is false; restrict YAN swing to vertical (#16199) 2026-06-03 13:38:00 -04:00
dependabot[bot]
87735d71a0 Bump actions/checkout from 6.0.2 to 6.0.3 (#16776)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 11:46:22 -04:00
dependabot[bot]
eba70dc193 Bump github/codeql-action from 4.36.0 to 4.36.1 (#16775)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 11:46:07 -04:00
dependabot[bot]
712ef2ec0e Bump esptool from 5.2.0 to 5.3.0 (#16774)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 11:45:52 -04:00
Clyde Stubbs
2009f6cc5f [lvgl] Fix indicator updates (#16780) 2026-06-03 11:43:48 -04:00
PolarGoose
89ddd34cb9 [dmsr] [breaking] Fix decryption that uses custom auth key. Add CRC to telegram sensor. Automatic hex string detection in equipment_id fields. Support EON Hungary smart meters (#16561) 2026-06-03 10:55:51 -04:00
Jonathan Swoboda
e4980713d1 [core] esphome clean wipes the whole build directory (#16772) 2026-06-03 07:35:23 -04:00
Clyde Stubbs
997ab11687 [lvgl][mipi_spi][mipi_rgb][mipi_dsi][display] Metadata (#16702) 2026-06-03 15:21:33 +10:00
Jesse Hills
792e1ff304 [i2c] Add basic host platform support (#14489)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-03 07:12:50 +12:00
Kevin Ahrendt
063770bcf4 [i2s_audio] Fix speaker DMA buffer sizing and validate bit depth at compile time (#16672) 2026-06-02 09:32:27 -04:00
Jesse Hills
6197282f1a Merge branch 'release' into dev 2026-06-02 15:40:28 +12:00
Jesse Hills
9c0ffee020 Merge pull request #16760 from esphome/bump-2026.5.2
2026.5.2
2026-06-02 15:39:40 +12:00
Bonne Eggleston
1740e54105 [ci] Fix auto label platform restructure false positive (#16734)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-01 23:20:18 -04:00
Jesse Hills
070c14b04a Bump version to 2026.5.2 2026-06-02 14:33:41 +12:00
J. Nick Koston
559cfd1555 [api] Fix crash loop on VoiceAssistantConfigurationRequest (#16757) 2026-06-02 14:33:41 +12:00
Jonathan Swoboda
571a12ffe5 [core] Clean build when the toolchain changes (#16744) 2026-06-02 14:33:41 +12:00
J. Nick Koston
a4d247fa0a [core] Persist esphome.area in StorageJSON (#16710) 2026-06-02 14:33:41 +12:00
Fyleo
8e57894af7 [sx126x] fix a typo in image calibration on 863 - 870 Mhz frequency (#16731) 2026-06-02 14:33:41 +12:00
J. Nick Koston
f9aba18f8e [libretiny] Fix RTL8710B IRAM_ATTR section being dropped from flashed image (#16616) 2026-06-02 14:33:41 +12:00
Jesse Hills
a04f6da814 [packages] Resolve git symlinks on Windows when materialized as text (#16657) 2026-06-02 14:33:41 +12:00
Jonathan Swoboda
3f57117efd [esp32] Decode crash PCs via IDF toolchain on IDF builds (#16626) 2026-06-02 14:33:41 +12:00
J. Nick Koston
d7f809181a [writer] Mark storage_should_clean as public API for device-builder (#16443) 2026-06-02 14:33:41 +12:00
Clyde Stubbs
d7d20f4f6b [cli] Allow state reporting control via env (#16746) 2026-06-02 07:04:35 +10:00
J. Nick Koston
ab46f8bd74 [api] Fix crash loop on VoiceAssistantConfigurationRequest (#16757) 2026-06-01 20:32:23 +00:00
Keith Burzinski
2454ad1645 [ethernet] Add enable_on_boot lifecycle + lazy-init to reclaim DMA-capable SRAM (#16607)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-06-01 15:30:07 -05:00
Keith Burzinski
4e48682468 [wifi] Defer esp_wifi_init() to lazy-init so enable_on_boot: false actually saves RAM (#16606)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 14:18:29 -05:00
Clyde Stubbs
805aa252d5 [const] Move CONF_SHA256 to common code (#16751) 2026-06-01 13:30:05 -04:00
Jonathan Swoboda
6116d10ab1 [espidf] Derive idedata from the native ESP-IDF compile_commands.json (#16742) 2026-05-31 17:44:12 -04:00
Jonathan Swoboda
48844a68ba [core] Clean build when the toolchain changes (#16744) 2026-05-31 16:29:16 -04:00
Jonathan Swoboda
7865dc33bc [ethernet] Bump espressif/dm9051 to 1.1.0 (#16735) 2026-05-31 09:50:17 -05:00
Jonathan Swoboda
bf62124032 [esp32] Refine ESP-IDF framework version suffix handling (#16726) 2026-05-30 07:43:21 -04:00
dependabot[bot]
95397948b9 Bump CodSpeedHQ/action from 4.15.1 to 4.17.0 (#16730)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-30 00:09:27 -05:00
J. Nick Koston
f0202155b3 [core] Persist esphome.area in StorageJSON (#16710) 2026-05-30 00:09:07 -05:00
Fyleo
07a57d7557 [sx126x] fix a typo in image calibration on 863 - 870 Mhz frequency (#16731) 2026-05-29 23:03:42 -04:00
Jonathan Swoboda
091a05ccde [esp32_camera] Enable PicolibC Newlib compatibility on IDF 6.0+ (#16703) 2026-05-29 05:16:55 +00:00
Jonathan Swoboda
dd961156d0 [ledc] Adapt to LEDC LL API changes in ESP-IDF 6.1 (#16697) 2026-05-29 00:54:14 -04:00
Jonathan Swoboda
10abb0647c [esp32] Add ESP32-S31, ESP32-H4 and ESP32-H21 variant scaffolding (#16700) 2026-05-29 00:30:52 -04:00
Jonathan Swoboda
a85f8ad935 [core] Use esp_rom_crc.h public API instead of legacy rom/crc.h (#16698) 2026-05-29 00:28:08 -04:00
dependabot[bot]
8945550c6c Bump ruff from 0.15.14 to 0.15.15 (#16712)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-29 03:35:37 +00:00
dependabot[bot]
4b8e06b5bc Bump tornado from 6.5.5 to 6.5.6 (#16704)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 09:12:35 -04:00
Mischa Siekmann
f41866a9b8 [gpio][binary_sensor] Fix pin validation for external GPIO pins (#16528) 2026-05-28 09:11:48 -04:00
tomaszduda23
5732d7135f [network] move ipv6 enforcement to validation step (#16701) 2026-05-28 08:39:11 -04:00
Jesse Hills
ec597bfc03 [docs] Update esphome-docs references to esphome.io after repo rename (#16705) 2026-05-28 14:54:42 +12:00
rwrozelle
9a6157b469 [tests] Sandbox PlatformIO paths in test_writer to fix xdist race (#16619)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-27 15:50:43 -04:00
GuzTech
ac29fad120 [growatt_solar] Replace hard coded register addresses with constexpr (#16581) 2026-05-27 14:21:50 -04:00
SoCuul
e87190edb4 [midea] fix casing of custom fan modes (#16419) 2026-05-27 14:20:00 -04:00
Elvin Luff
911e330c09 [core] Add Codeberg as a supported git url (#16501) 2026-05-27 14:13:03 -04:00
Jonathan Swoboda
e64b6bc398 [esp32] Stub arduino-esp32 with INTERFACE re-export to framework (#16695) 2026-05-27 11:00:51 -04:00
J. Nick Koston
21e548f1d7 [core] Sensitive redaction via yaml_util representer (#16690) 2026-05-27 09:20:50 -05:00
J. Nick Koston
3cc875c40b [core] Enable ruff BLE (flake8-blind-except) lint family (#16659) 2026-05-27 20:09:57 +12:00
Ardumine
7463a15c7e [network] Add Zephyr IPv6 networking support for nRF52 (#16336)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: tomaszduda23 <tomaszduda23@gmail.com>
2026-05-27 07:43:38 +00:00
dependabot[bot]
8d19c55be2 Bump pytest-asyncio from 1.3.0 to 1.4.0 (#16687)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 19:58:13 -05:00
dependabot[bot]
87d0e24d19 Bump aioesphomeapi from 45.2.2 to 45.3.1 (#16688)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-26 19:57:29 -05:00
J. Nick Koston
91ead4ff54 [core] Mark canonical sensitive fields with cv.sensitive (#16677) 2026-05-27 00:16:47 +00:00
Jonathan Swoboda
a6ef67aa65 [text_sensor] Remove deprecated public raw_state member (#16683) 2026-05-26 23:34:52 +00:00
Jonathan Swoboda
e174c44b28 [neopixelbus] Deprecate on ESP32 (#16676) 2026-05-26 19:15:25 -04:00
Jonathan Swoboda
f728cb4373 [core] Remove deprecated seq/gens templates (#16685) 2026-05-26 18:50:20 -04:00
Jonathan Swoboda
6c4a8a3245 [dsmr] Force BearSSL on ESP8266 to avoid mbedtls link failure (#16686) 2026-05-26 22:49:44 +00:00
Jonathan Swoboda
eb1196c6b2 [nfc] Remove deprecated heap-allocating format helpers (#16684) 2026-05-26 18:48:17 -04:00
Jonathan Swoboda
fb0b73980b [wifi] Default ESP8266 min_auth_mode to WPA2 (#16682) 2026-05-26 18:47:40 -04:00
Jonathan Swoboda
171ded35a5 [core] Remove cv.only_with_esp_idf and CORE.using_esp_idf (#16681) 2026-05-26 18:47:16 -04:00
Jonathan Swoboda
b71d445e79 [core] Remove deprecated const char* mark_failed/status_set_error (#16680) 2026-05-26 18:46:45 -04:00
Jonathan Swoboda
4d908798bc [core] Remove deprecated custom_components folder loading (#16679) 2026-05-26 18:45:50 -04:00
Clyde Stubbs
62b3b1cc75 [lvgl] Support rounded property for meter arcs (#16669) 2026-05-26 15:30:08 -05:00
J. Nick Koston
52ead52ef2 [core] Enable ruff PGH (pygrep-hooks) lint family (#16651) 2026-05-26 15:29:54 -05:00
J. Nick Koston
96816e2491 [core] Enable ruff DTZ (flake8-datetimez) lint family (#16660) 2026-05-26 15:29:38 -05:00
J. Nick Koston
bac62cb7de [core] Add cv.sensitive marker for schema-level sensitive fields (#16673) 2026-05-26 15:29:06 -05:00
Kevin Ahrendt
722cbfe843 [voice_assistant] Never send zero-length audio to Home Assistant (#16634) 2026-05-26 14:05:57 -04:00
J. Nick Koston
88b12a1c45 [lvgl] Build automation_schema event validators lazily (#16633) 2026-05-26 08:41:54 -05:00
J. Nick Koston
ceb9d406e1 [core] Enable ruff PIE (flake8-pie) lint family (#16658) 2026-05-26 07:46:44 -04:00
J. Nick Koston
8b62cfded7 [libretiny] Fix RTL8710B IRAM_ATTR section being dropped from flashed image (#16616) 2026-05-26 19:57:44 +12:00
Jesse Hills
423b60c90c [packages] Resolve git symlinks on Windows when materialized as text (#16657) 2026-05-26 19:56:44 +12:00
J. Nick Koston
ae74920b81 [core] Enable ruff PTH (flake8-use-pathlib) lint family (#16661) 2026-05-26 05:14:42 +00:00
J. Nick Koston
ae814cff5c [core] Enable ruff B (flake8-bugbear) lint family (#16655) 2026-05-26 02:28:14 +00:00
J. Nick Koston
489cf483d0 [core] Enable ruff PYI (flake8-pyi) lint family (#16654) 2026-05-25 20:55:35 -05:00
J. Nick Koston
dd0028c1b5 [core] Enable ruff G (flake8-logging-format) lint family (#16650) 2026-05-26 01:36:49 +00:00
J. Nick Koston
e492f8f8b6 [tests] Disable hypothesis deadline on flaky IP address test (#16652) 2026-05-25 20:14:36 -05:00
J. Nick Koston
b39b34bfe1 [core] Enable ruff C4 (flake8-comprehensions) lint family (#16653) 2026-05-25 20:14:26 -05:00
J. Nick Koston
bbc24ab546 [core] Enable ruff RSE (flake8-raise) lint family (#16649) 2026-05-25 20:06:34 -05:00
J. Nick Koston
f1839489dd [core] Enable ruff ISC (flake8-implicit-str-concat) lint family (#16646) 2026-05-25 20:06:18 -05:00
J. Nick Koston
5172227931 [core] Enable ruff SLOT (flake8-slots) lint family (#16647) 2026-05-25 20:06:01 -05:00
J. Nick Koston
97267105e1 [core] Enable ruff EXE (flake8-executable) lint family (#16648) 2026-05-25 20:05:51 -05:00
J. Nick Koston
8645f3672d [core] Enable additional zero-violation ruff lint families (#16645) 2026-05-25 18:11:40 -05:00
Boris Krivonog
a257edba62 [mitsubishi_cn105] Add basic swing support (#15653)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-25 16:46:33 -05:00
Jonathan Swoboda
61e8830a3c [espidf] Keep cmake output filter working when IDF writes raw bytes (#16642) 2026-05-25 17:40:38 -04:00
Jonathan Swoboda
fc0a4e2201 [espidf] Support github:// and https://github.com/.../.git framework sources (#16639) 2026-05-25 17:07:35 -04:00
Clyde Stubbs
0b780f1fd2 [time][homeassistant] Fix timezone handling (#16583) 2026-05-26 06:51:15 +10:00
Kevin Ahrendt
dcc30f8651 [router] Share a single I2S bus in test (#16637) 2026-05-25 15:39:54 -04:00
Kevin Ahrendt
892e116680 [router] Add a router speaker component to runtime choose output speaker (#16592) 2026-05-25 12:42:49 -04:00
Kevin Ahrendt
1c7ae96e42 [micro_wake_word] Allow task stack to be allocated in PSRAM (#16632) 2026-05-25 11:04:26 -04:00
Jonathan Swoboda
684bce8b9a [esp32] Decode crash PCs via IDF toolchain on IDF builds (#16626) 2026-05-25 14:36:41 +00:00
Kevin Ahrendt
7c494fd3ef [psram] Consolidate task stack in PSRAM handling (#16628) 2026-05-25 10:15:51 -04:00
Jonathan Swoboda
cf1fabe6d4 [esp32_hosted] Bump esp_hosted to 2.12.8 and add use_psram option (#16627) 2026-05-25 10:11:31 -04:00
J. Nick Koston
cde52ef75e [lvgl] Merge dict-extend chains to speed up schema construction (#16614) 2026-05-25 09:09:54 -05:00
Jonathan Swoboda
98e7213387 [espidf] Warn instead of skipping libraries with framework mismatch (#16630) 2026-05-25 14:08:16 +00:00
Jonathan Swoboda
e7ab78366d [core] Add esphome.build_flags option for IDF + PlatformIO (#16629) 2026-05-25 10:03:38 -04:00
J. Nick Koston
e0167e9bdf [lvgl] Memoize obj_schema by widget_type (#16615) 2026-05-24 20:17:51 -05:00
Jesse Hills
62b0a93e5e [rp2040] Add variant config option for RP2040/RP2350 (#16602) 2026-05-25 10:43:39 +12:00
Jesse Hills
1fb8c26704 Merge branch 'release' into dev 2026-05-25 10:43:04 +12:00
Jesse Hills
3d1a614e55 Merge pull request #16610 from esphome/bump-2026.5.1
2026.5.1
2026-05-25 10:42:20 +12:00
dependabot[bot]
917ffc3797 Bump aioesphomeapi from 45.0.4 to 45.2.2 (#16611)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-24 21:49:52 +00:00
J. Nick Koston
090f5a486a Lift dependabot pip open PR limit (#16609) 2026-05-24 16:32:47 -05:00
Jesse Hills
03e2eb4b4a Bump version to 2026.5.1 2026-05-25 09:28:49 +12:00
Jonathan Swoboda
ddd353d105 [esp32] Disable IDF's COMPILER_DISABLE_DEFAULT_ERRORS so -Wno-error actually undoes -Werror (#16604) 2026-05-25 09:28:49 +12:00
Jonathan Swoboda
9a34a6aabb [esp32] Replace per-class -Wno-error=X demotes with blanket -Wno-error for ESP-IDF toolchain (#16599) 2026-05-25 09:28:49 +12:00
J. Nick Koston
0babc52472 [bluetooth_proxy] Recover slot stuck in DISCONNECTING when CLOSE_EVT is dropped (#16588) 2026-05-25 09:28:49 +12:00
Jonathan Swoboda
adde7681e8 [esp32] Demote IDF #warning deprecations from error under ESP-IDF toolchain (#16584) 2026-05-25 09:28:49 +12:00
J. Nick Koston
8f6ea62628 [uart] Wake main loop on ESP8266 software serial RX (#16562) 2026-05-25 09:28:49 +12:00
J. Nick Koston
4e7bc92061 [esp8266] Use os_timer-based esp_delay() in delay() (#16563) 2026-05-25 09:28:49 +12:00
Edvard Filistovič
1f4a061572 [libretiny] Fix LN882H IRAM_ATTR injection point in patch_linker.py (#16570) 2026-05-25 09:28:49 +12:00
J. Nick Koston
59db9a4673 [dashboard] Fix flaky test_websocket_refresh_command on Windows CI (#16565) 2026-05-25 09:28:49 +12:00
Kevin Ahrendt
7ae5566472 [sendspin] Bump sendspin-cpp to v0.6.1 (#16553) 2026-05-25 09:28:49 +12:00
J. Nick Koston
f247def4ac [core] Refresh compiled config cache after upload/logs fallback (#16548) 2026-05-25 09:28:49 +12:00
Jonathan Swoboda
27d53ec117 [sx126x] Assert NSS before wait_busy so commands wake the chip from sleep (#16546) 2026-05-25 09:28:49 +12:00
J. Nick Koston
0c94a173b6 [api] Break api_connection/api_server include cycle to drop custom unique_ptr deleter (#16542) 2026-05-25 09:28:49 +12:00
Jonathan Swoboda
ae2e372762 [tuya] Restore null guard on status_pin lost in #16353 (#16539) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
e6ed275746 [esp32] Defer esp_panic_handler wrap so arduino-esp32 IDF component skips it (#16538) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
878027ff50 [espidf] Honor the dict shorthand for library.json dependencies (#16537) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
858cfd5b94 [espidf] Default to remote HEAD when cg.add_library URL has no #ref (#16535) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
5225416347 [espidf] Backport ninja linux-arm64 entry into tools.json on aarch64 hosts (#16527) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
615d5aa827 [core] Persist & restore CORE.toolchain through StorageJSON (#16531) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
e92a4c9472 [espidf] Write version.txt after extract so bootloader shows the real version (#16532) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
32fa856bf0 [espidf] Fix tarfile extract crashing on Python 3.11 with None mode (#16530) 2026-05-25 09:28:48 +12:00
Jonathan Swoboda
cc88456ce7 [espidf] Filter noisy 'git rev-parse' errors when .git is stripped (#16521) 2026-05-25 09:28:48 +12:00
dependabot[bot]
79539cb85d Bump zeroconf from 0.149.13 to 0.149.16 (#16533)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 09:28:48 +12:00
dependabot[bot]
16b6509a03 Bump zeroconf from 0.149.12 to 0.149.13 (#16520)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 09:28:48 +12:00
Kevin Ahrendt
9fcb638f33 [micro_wake_word] Use RingBufferAudioSource (#16595)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-24 15:34:51 -04:00
Kevin Ahrendt
747787ae98 [audio] Use RingBufferAudioSource for resampling (#16560) 2026-05-24 15:34:15 -04:00
Kevin Ahrendt
5cb7e62241 [audio] Use RingBufferAudioSource for decoding (#16564) 2026-05-24 15:33:32 -04:00
Kevin Ahrendt
c17c4478ac [mixer] Support any bit depth audio (#16524) 2026-05-24 15:32:43 -04:00
Kevin Ahrendt
750d52741a [voice_assistant] Use RingBufferAudioSource (#16597) 2026-05-24 08:36:53 -04:00
Rodrigo Martín
a37f27ee7f [espnow, ethernet, network, openthread, wifi] centralize network initialization for ESP32 (#14012)
Co-authored-by: kbx81 <kbx81x@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-05-24 05:27:31 +00:00
Jonathan Swoboda
5f860ff5bd [esp32] Disable IDF's COMPILER_DISABLE_DEFAULT_ERRORS so -Wno-error actually undoes -Werror (#16604) 2026-05-24 04:19:07 +00:00
Keith Burzinski
c951881eea [api] Fix uint32_t/int32_t format strings for stricter GCC toolchain (#16603) 2026-05-24 04:05:18 +00:00
Kevin Ahrendt
5cb145a8c3 [ethernet] Offload W5500 bulk SPI transfers from the busy-wait path (#16596) 2026-05-23 17:53:53 -04:00
Kevin Ahrendt
74001ccf05 [wifi] Wake main loop when requesting high performance mode (#16598) 2026-05-23 17:39:20 -04:00
Kevin Ahrendt
58931f2610 [audio] Add clear_buffered_data method to RingBufferAudioSource (#16594) 2026-05-23 17:37:59 -04:00
Jonathan Swoboda
f616103621 [esp32] Replace per-class -Wno-error=X demotes with blanket -Wno-error for ESP-IDF toolchain (#16599) 2026-05-23 15:44:25 -04:00
J. Nick Koston
188ff7ebfd [bluetooth_proxy] Recover slot stuck in DISCONNECTING when CLOSE_EVT is dropped (#16588) 2026-05-23 14:30:12 -05:00
Clyde Stubbs
be99553fd4 [ci] Fix flash memory overflow on tests (#16587) 2026-05-23 14:26:53 +10:00
Jonathan Swoboda
b0dc688c14 [esp32] Demote IDF #warning deprecations from error under ESP-IDF toolchain (#16584) 2026-05-22 20:30:25 -04:00
J. Nick Koston
2b422cbd99 [lvgl] Build widget update action schemas lazily (#16569)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2026-05-23 00:20:39 +00:00
dependabot[bot]
9930b3c216 Bump github/codeql-action from 4.35.5 to 4.36.0 (#16579)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 19:18:31 -05:00
dependabot[bot]
55f4e5cb75 Bump the docker-actions group across 1 directory with 2 updates (#16578)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 19:18:20 -05:00
J. Nick Koston
71550bb3be [lvgl] Memoize and lazily build container_schema (#16567) 2026-05-22 18:39:25 -05:00
J. Nick Koston
a58b4edb6a [ci] Gate unconditional CI jobs on a single determine-jobs output instead of a path filter (#16580) 2026-05-22 18:39:06 -05:00
Clyde Stubbs
f85fdb475a [homeassistant] Reduce log spam for sensors (#16555) 2026-05-23 08:07:51 +10:00
dependabot[bot]
4a78c8d45a Bump pytest-codspeed from 5.0.2 to 5.0.3 (#16575)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 15:55:49 -05:00
Kevin Ahrendt
c3bef24389 [i2s_audio] Reset dout GPIO when stopping speaker driver (#16573) 2026-05-22 14:43:50 -05:00
J. Nick Koston
7182b1a8ae [uart] Wake main loop on ESP8266 software serial RX (#16562) 2026-05-22 14:30:43 -05:00
J. Nick Koston
64e32ebe04 [esp8266] Use os_timer-based esp_delay() in delay() (#16563) 2026-05-22 14:30:28 -05:00
Edvard Filistovič
94b10981e1 [libretiny] Fix LN882H IRAM_ATTR injection point in patch_linker.py (#16570) 2026-05-22 14:09:32 -05:00
J. Nick Koston
680c9fc9c0 [dashboard] Fix flaky test_websocket_refresh_command on Windows CI (#16565) 2026-05-22 08:49:03 -05:00
dependabot[bot]
99de741f99 Bump docker/build-push-action from 7.1.0 to 7.2.0 in /.github/actions/build-image (#16545)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 08:08:29 -05:00
dependabot[bot]
ac530c33b0 Bump actions/stale from 10.2.0 to 10.3.0 (#16544)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 08:08:14 -05:00
Kevin Ahrendt
0b5e7ae8fa [sendspin] Bump sendspin-cpp to v0.6.1 (#16553) 2026-05-22 06:43:08 -04:00
Jesse Hills
0b2eb6481f [light] Add light.effect.next / light.effect.previous actions (#16491) 2026-05-22 13:42:50 +12:00
Jesse Hills
1d3eea098e [core] Support YAML frontmatter for arbitrary user metadata (#16552) 2026-05-22 13:00:22 +12:00
dependabot[bot]
4ff8eb4b15 Bump ruff from 0.15.13 to 0.15.14 (#16543)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-21 22:08:56 +00:00
J. Nick Koston
aea1e4d136 [core] Refresh compiled config cache after upload/logs fallback (#16548) 2026-05-21 17:05:17 -05:00
Jonathan Swoboda
38b8b41ccc [sx126x] Assert NSS before wait_busy so commands wake the chip from sleep (#16546) 2026-05-21 18:03:07 -04:00
J. Nick Koston
96eced0378 [api] Break api_connection/api_server include cycle to drop custom unique_ptr deleter (#16542) 2026-05-21 15:42:57 -05:00
Jonathan Swoboda
1ea95264bd [tuya] Restore null guard on status_pin lost in #16353 (#16539) 2026-05-21 18:08:09 +00:00
Jonathan Swoboda
d2bda0a402 [esp32] Defer esp_panic_handler wrap so arduino-esp32 IDF component skips it (#16538) 2026-05-21 14:03:55 -04:00
Jonathan Swoboda
56fd77e4c8 [espidf] Honor the dict shorthand for library.json dependencies (#16537) 2026-05-21 13:01:54 -05:00
Jonathan Swoboda
3719ea740a [espidf] Default to remote HEAD when cg.add_library URL has no #ref (#16535) 2026-05-21 13:01:19 -05:00
Jonathan Swoboda
750ae56778 [espidf] Backport ninja linux-arm64 entry into tools.json on aarch64 hosts (#16527) 2026-05-21 12:05:27 -04:00
Kevin Ahrendt
01494f7431 [audio] Bump esp-audio-libs to v3.1.0 (#16519) 2026-05-21 11:57:32 -04:00
J. Nick Koston
233a60f106 [ci] Pin uv version in setup-uv to fix Windows manifest fetch flake (#16534) 2026-05-21 10:53:34 -05:00
Jonathan Swoboda
e0076cb1a8 [core] Persist & restore CORE.toolchain through StorageJSON (#16531) 2026-05-21 10:37:46 -05:00
Jonathan Swoboda
b619e3e8c7 [espidf] Write version.txt after extract so bootloader shows the real version (#16532) 2026-05-21 10:37:10 -05:00
Jonathan Swoboda
f2bfe5cd17 [espidf] Fix tarfile extract crashing on Python 3.11 with None mode (#16530) 2026-05-21 10:36:27 -05:00
Jonathan Swoboda
90715373f2 [espidf] Filter noisy 'git rev-parse' errors when .git is stripped (#16521) 2026-05-21 10:35:51 -05:00
Jonathan Swoboda
52e7d3ccfb [esp32] Use new sdkconfig key names that replaced deprecated ones (#16522) 2026-05-21 10:35:25 -05:00
dependabot[bot]
a70e358cea Bump zeroconf from 0.149.13 to 0.149.16 (#16533)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-21 09:55:28 -05:00
dependabot[bot]
43a1c2067e Bump zeroconf from 0.149.12 to 0.149.13 (#16520)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-21 08:28:09 -05:00
Jesse Hills
11760307f7 Merge branch 'release' into dev 2026-05-21 13:49:17 +12:00
Jesse Hills
15c546b809 Merge pull request #16523 from esphome/bump-2026.5.0
2026.5.0
2026-05-21 13:48:28 +12:00
Jesse Hills
104c8bed41 Bump version to 2026.5.0 2026-05-21 11:16:58 +12:00
Jesse Hills
49bfa12eb7 Merge branch 'beta' into dev 2026-05-21 10:14:14 +12:00
Jesse Hills
ca859de212 Merge pull request #16518 from esphome/bump-2026.5.0b4
2026.5.0b4
2026-05-21 10:13:39 +12:00
Jesse Hills
de783e72d5 Bump version to 2026.5.0b4 2026-05-21 09:10:52 +12:00
Jonathan Swoboda
cd7e2d79c4 [esp32] Decouple esp-idf toolchain version check from PIO, honor framework source: override (#16516) 2026-05-21 09:10:52 +12:00
Jonathan Swoboda
ecf823b871 [espidf] Drop version field from generated idf_component.yml (#16511) 2026-05-21 09:10:52 +12:00
dependabot[bot]
9fdad68138 Bump aioesphomeapi from 45.0.3 to 45.0.4 (#16513)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-21 09:10:51 +12:00
dependabot[bot]
b79a306d02 Bump zeroconf from 0.149.7 to 0.149.12 (#16510)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-21 09:10:51 +12:00
Jonathan Swoboda
870f628637 [esp32] Decouple esp-idf toolchain version check from PIO, honor framework source: override (#16516) 2026-05-20 20:40:59 +00:00
Jonathan Swoboda
52c9a2d07b [espidf] Drop version field from generated idf_component.yml (#16511) 2026-05-20 14:31:58 -04:00
Jonathan Swoboda
60afad442c [esp32] Fix sdkconfig int values silently clamped to default (#16515) 2026-05-20 13:36:18 -04:00
dependabot[bot]
fbe212944b Bump aioesphomeapi from 45.0.3 to 45.0.4 (#16513)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 10:51:53 -05:00
dependabot[bot]
8927ade789 Bump zeroconf from 0.149.7 to 0.149.12 (#16510)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 15:40:20 +00:00
Jesse Hills
63fe977adb Merge branch 'beta' into dev 2026-05-20 14:34:33 +12:00
Jesse Hills
94badfcb19 Merge pull request #16507 from esphome/bump-2026.5.0b3
2026.5.0b3
2026-05-20 14:33:57 +12:00
Jesse Hills
19c4da2aa5 Bump version to 2026.5.0b3 2026-05-20 12:53:26 +12:00
Kevin Ahrendt
e4c8d1f430 [sendspin] Bump sendspin to v0.6.0 (#16496) 2026-05-20 12:53:26 +12:00
Kevin Ahrendt
302938f875 [i2s_audio] Optimize SPDIF encoder and suport higher bit depth audio (#16504)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2026-05-20 12:53:26 +12:00
Jonathan Swoboda
65e1e210de [espidf] Print RAM summary on ESP32-S3 / unified-DIRAM variants (#16494) 2026-05-20 12:53:26 +12:00
luar123
43cc9fc879 [zigbee] don't allow zigbee + thread or access point (#16499) 2026-05-20 12:53:25 +12:00
Kevin Ahrendt
41ad2ba763 [i2s_audio] Compute ring buffer size with SPDIF sample count (#16400) 2026-05-20 12:53:25 +12:00
Brandon Harvey
25739091da [sen6x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16465) 2026-05-20 12:53:25 +12:00
Brandon Harvey
bbf5fe8450 [sgp4x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16464) 2026-05-20 12:53:25 +12:00
Brandon Harvey
e9ef58d99d [sen5x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16463) 2026-05-20 12:53:25 +12:00
dependabot[bot]
e1793a1eff Bump zeroconf from 0.149.3 to 0.149.7 (#16492)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 12:53:25 +12:00
Jesse Hills
9bb70d568d [ci] Move ha-addon and schema release triggers to version-notifier (#16490) 2026-05-20 12:53:25 +12:00
Kevin Ahrendt
0912122634 [sendspin] Bump sendspin to v0.6.0 (#16496) 2026-05-19 15:16:00 -04:00
Kevin Ahrendt
9924d998f1 [i2s_audio] Optimize SPDIF encoder and suport higher bit depth audio (#16504)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2026-05-19 13:37:41 -05:00
dependabot[bot]
e979d461f0 Bump codecov/codecov-action from 6.0.0 to 6.0.1 (#16500)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-19 12:15:50 -05:00
J. Nick Koston
863af482ec [esp32_ble_server] Honor client offset and MTU in long reads (#16458) 2026-05-19 12:14:15 -05:00
J. Nick Koston
80ed541032 [core] Add progmem_memcpy HAL helper (#16470) 2026-05-19 12:13:58 -05:00
Jonathan Swoboda
1d0ddfac5d [espidf] Print RAM summary on ESP32-S3 / unified-DIRAM variants (#16494) 2026-05-19 12:57:18 -04:00
luar123
c0e71fc713 [zigbee] don't allow zigbee + thread or access point (#16499) 2026-05-19 12:53:36 -04:00
Kevin Ahrendt
7ecfe4b5c9 [i2s_audio] Compute ring buffer size with SPDIF sample count (#16400) 2026-05-18 21:53:19 -05:00
Brandon Harvey
36fc36071d [sen6x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16465) 2026-05-19 11:20:08 +12:00
Brandon Harvey
cb581271ed [sgp4x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16464) 2026-05-19 11:19:51 +12:00
Brandon Harvey
b0af4a9f0d [sen5x] Remove incorrect AQI device class from VOC and NOx Index sensors (#16463) 2026-05-19 11:19:48 +12:00
dependabot[bot]
edb59476b1 Bump zeroconf from 0.149.3 to 0.149.7 (#16492)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 23:29:03 -07:00
Jesse Hills
9c696f5de1 [ci] Move ha-addon and schema release triggers to version-notifier (#16490) 2026-05-18 15:56:44 +12:00
Jesse Hills
6804965bd8 Merge branch 'beta' into dev 2026-05-18 15:31:01 +12:00
Jesse Hills
213df0412d Merge pull request #16488 from esphome/bump-2026.5.0b2
2026.5.0b2
2026-05-18 15:28:53 +12:00
Jesse Hills
cdf74c180e Bump version to 2026.5.0b2 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
df31c72e4e [espidf] Switch direct framework downloader to esphome-libs/esp-idf tarballs (#16484) 2026-05-18 11:11:54 +12:00
dependabot[bot]
4f188bf9bb Bump zeroconf from 0.148.0 to 0.149.3 (#16480)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 11:11:54 +12:00
dependabot[bot]
20f92ad5e9 Bump aioesphomeapi from 45.0.2 to 45.0.3 (#16479)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 11:11:54 +12:00
J. Nick Koston
f301e90fd9 [ci] Use larger app partition for esp32-s3-idf component test grouping (#16430) 2026-05-18 11:11:54 +12:00
dependabot[bot]
2dbaaf1efd Bump aioesphomeapi from 45.0.1 to 45.0.2 (#16469)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 11:11:54 +12:00
Clyde Stubbs
da237b5070 [lvgl] Fix image define (#16468) 2026-05-18 11:11:54 +12:00
Clyde Stubbs
6a8f24b951 [ft5x06] Fix setting calibration values (#16446) 2026-05-18 11:11:54 +12:00
dependabot[bot]
26907f17f5 Bump aioesphomeapi from 45.0.0 to 45.0.1 (#16467)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 11:11:54 +12:00
Jonathan Swoboda
c6a74222f1 [esp32_hosted][fingerprint_grow] Fix two remaining ESP32 toolchain warnings (#16442) 2026-05-18 11:11:54 +12:00
J. Nick Koston
5ec0879a10 [core] Fix KeyError: 'esp32' on upload when validated-config cache is used (#16457) 2026-05-18 11:11:54 +12:00
J. Nick Koston
50495c7085 [wifi] Refuse to compile when wifi_ssid is the device-builder placeholder (#16444) 2026-05-18 11:11:54 +12:00
Kevin Ahrendt
25dbef83de [sound_level] Use RingBufferAudioSource (#16436) 2026-05-18 11:11:54 +12:00
Kevin Ahrendt
4f895425ca [audio] Bump microMP3 to v0.2.1 (#16429) 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
c037058c19 [esp32_hosted] Bump esp_hosted to 2.12.7 (#16440) 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
ecac6b64ec [espidf] Gate esp_idf_size --ng on IDF version (#16441) 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
3831aa809f [multiple] Fix -Wformat= mismatches in component .cpp sources (#16433) 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
da8286f554 [docker] Install libusb-1.0 so ESP-IDF tools can validate openocd (#16424)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-18 11:11:54 +12:00
Jonathan Swoboda
d5c6efb2fe [tests] Fix -Wformat= mismatches in test YAML lambdas/logger.log (#16435) 2026-05-18 11:11:54 +12:00
Jonathan Swoboda
dd1818661c [esp32] Sweep ESP-IDF toolchain warnings + bump deprecated mark_failed (#16432) 2026-05-18 11:11:53 +12:00
Keith Burzinski
fb659f9ac4 [tinyusb] Reject logger.hardware_uart: USB_CDC (#16417)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 11:11:53 +12:00
Keith Burzinski
ab273a1f8f [tinyusb] Reject tinyusb: configured without a USB class companion (#16413)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 11:11:53 +12:00
Jonathan Swoboda
84b5931299 [espidf] Trim has_outdated_files watch list; embed IDF version in sdkconfig (#16416) 2026-05-18 11:11:53 +12:00
Jonathan Swoboda
c863d58999 [espidf] Stop perpetual reconfigure loop on native ESP-IDF builds (#16415) 2026-05-18 11:11:53 +12:00
Jesse Hills
42ad2a6272 [espidf] Accept list input in _str_to_lst_of_str helper (#16485) 2026-05-18 10:49:03 +12:00
Jonathan Swoboda
6690725860 [espidf] Switch direct framework downloader to esphome-libs/esp-idf tarballs (#16484) 2026-05-18 07:29:38 +12:00
dependabot[bot]
155232875a Bump zeroconf from 0.148.0 to 0.149.3 (#16480)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-16 19:08:19 -07:00
dependabot[bot]
01c0d3163e Bump aioesphomeapi from 45.0.2 to 45.0.3 (#16479)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-16 18:41:09 -07:00
J. Nick Koston
7c5d5f75dc [ci] Use larger app partition for esp32-s3-idf component test grouping (#16430) 2026-05-15 22:16:52 -07:00
dependabot[bot]
fb0bfea1c8 Bump aioesphomeapi from 45.0.1 to 45.0.2 (#16469)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 22:06:33 -07:00
J. Nick Koston
48d17571c8 [tests] Mock determine_cpp_unit_tests in clang_tidy_mode tests (#16456) 2026-05-15 15:50:58 -07:00
Clyde Stubbs
df100681e0 [lvgl] Fix image define (#16468) 2026-05-15 22:36:53 +00:00
Clyde Stubbs
1a287bf785 [ft5x06] Fix setting calibration values (#16446) 2026-05-16 10:30:04 +12:00
dependabot[bot]
ff34e1061b Bump resvg-py from 0.3.1 to 0.3.2 (#16466)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 14:43:08 -07:00
dependabot[bot]
b78b78cbbb Bump aioesphomeapi from 45.0.0 to 45.0.1 (#16467)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 14:42:51 -07:00
dependabot[bot]
4c090c6b85 Bump github/codeql-action from 4.35.4 to 4.35.5 (#16461)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 12:37:56 -07:00
dependabot[bot]
ec6669fa67 Bump requests from 2.34.1 to 2.34.2 (#16460)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 12:37:41 -07:00
dependabot[bot]
59f8c1019f Bump pytest-codspeed from 5.0.1 to 5.0.2 (#16459)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-15 12:37:28 -07:00
david-collett
fb70095ba1 [esp32_ble_server] Fix incorrect BLECharacteristic read truncation (#16420) (#16422)
Co-authored-by: Dave <dave@morty>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-15 10:47:26 -07:00
Jonathan Swoboda
65d6bb18ed [esp32_hosted][fingerprint_grow] Fix two remaining ESP32 toolchain warnings (#16442) 2026-05-15 17:32:51 +00:00
J. Nick Koston
47eb2adbf2 [core] Fix KeyError: 'esp32' on upload when validated-config cache is used (#16457) 2026-05-15 10:29:15 -07:00
J. Nick Koston
35631be260 [writer] Mark storage_should_clean as public API for device-builder (#16443) 2026-05-15 10:20:31 -07:00
J. Nick Koston
96106d25bc [wifi] Refuse to compile when wifi_ssid is the device-builder placeholder (#16444) 2026-05-15 10:20:15 -07:00
J. Nick Koston
1674ed9744 [ci] Use uv for pip installs across CI workflows (#16451) 2026-05-15 10:18:27 -07:00
J. Nick Koston
46be0f4f62 [ci] Log top 30 pytest durations (#16455) 2026-05-15 10:18:07 -07:00
J. Nick Koston
ec1826a6ed [yaml_util] Promote include-discovery helper, share it with bundle (#16447) 2026-05-15 10:17:50 -07:00
Simone Chemelli
8b3bc47547 [uptime] Update device_class for Uptime sensor (#16434)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-05-15 17:16:01 +00:00
J. Nick Koston
4381a8baaa [ci] pr-title-check: skip all bot authors, not just dependabot (#16453) 2026-05-15 09:59:35 -07:00
esphome[bot]
4189979391 Synchronise Device Classes from Home Assistant (#16452)
Co-authored-by: esphomebot <esphome@openhomefoundation.org>
2026-05-15 09:57:49 -07:00
J. Nick Koston
1b1e21d470 [ci] sync-device-classes: drop branch-switch hack, skip no-commit-to-branch instead (#16450) 2026-05-15 09:54:01 -07:00
J. Nick Koston
5b6c54c961 [ci] sync-device-classes: use uv for installs and skip pylint (#16449) 2026-05-15 09:45:11 -07:00
Jonathan Swoboda
ff968a4629 [ci] Fix sync-device-classes workflow (failing daily for weeks) (#16448) 2026-05-15 09:36:01 -07:00
Edward Firmo
d832ce51cd [nextion] Replace connect_info vector with fixed-size field parser, always log device info (#16059)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-14 22:42:10 -05:00
Kevin Ahrendt
d663d80fde [sound_level] Use RingBufferAudioSource (#16436) 2026-05-14 20:33:36 -07:00
Kevin Ahrendt
c5c627d534 [audio] Bump microMP3 to v0.2.1 (#16429) 2026-05-14 20:31:11 -07:00
Jonathan Swoboda
d046dd7276 [esp32_hosted] Bump esp_hosted to 2.12.7 (#16440) 2026-05-14 22:51:14 -04:00
Jonathan Swoboda
56983f414f [espidf] Gate esp_idf_size --ng on IDF version (#16441) 2026-05-14 22:41:36 -04:00
Jonathan Swoboda
a92b607754 [ci] Add ci-run-all label to force full CI matrix (#16421) 2026-05-14 18:54:13 -04:00
Jonathan Swoboda
313d974983 [multiple] Fix -Wformat= mismatches in component .cpp sources (#16433) 2026-05-14 18:53:42 -04:00
Jonathan Swoboda
1d86d856d1 [docker] Install libusb-1.0 so ESP-IDF tools can validate openocd (#16424)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-14 15:51:59 -07:00
Jonathan Swoboda
1bb191aa77 [ci] Skip dashboard-deprecation bot on release/beta-bump PRs (#16427) 2026-05-14 15:51:36 -07:00
dependabot[bot]
5d9d6e83f7 Bump ruff from 0.15.12 to 0.15.13 (#16437)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 15:41:32 -07:00
Jonathan Swoboda
f3d7743460 [tests] Fix -Wformat= mismatches in test YAML lambdas/logger.log (#16435) 2026-05-14 18:40:40 -04:00
Jonathan Swoboda
f291dc8d2f [esp32] Sweep ESP-IDF toolchain warnings + bump deprecated mark_failed (#16432) 2026-05-14 18:39:16 -04:00
Jonathan Swoboda
a8e69a15e4 [clang-tidy] Enable readability-container-contains (#16438) 2026-05-14 18:38:09 -04:00
Keith Burzinski
7436d1c199 [tinyusb] Reject logger.hardware_uart: USB_CDC (#16417)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 20:29:56 +00:00
Keith Burzinski
348b92910e [tinyusb] Reject tinyusb: configured without a USB class companion (#16413)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:07:38 -05:00
Jonathan Swoboda
f89a6f4f9c [espidf] Trim has_outdated_files watch list; embed IDF version in sdkconfig (#16416) 2026-05-14 04:02:22 +00:00
Jesse Hills
c3ee962b83 Merge branch 'beta' into dev 2026-05-14 15:25:38 +12:00
Jesse Hills
59847d56e8 Merge pull request #16411 from esphome/bump-2026.5.0b1
2026.5.0b1
2026-05-14 15:24:58 +12:00
Jonathan Swoboda
e593cb6efc [espidf] Stop perpetual reconfigure loop on native ESP-IDF builds (#16415) 2026-05-13 23:19:30 -04:00
J. Nick Koston
d2107e40c8 [ci] Prohibit curly braces in PR titles for MDX safety (#16412) 2026-05-14 14:03:45 +12:00
Jesse Hills
09a926fa13 Bump version to 2026.5.0b1 2026-05-14 12:33:43 +12:00
Jesse Hills
78b60ac6fa Bump version to 2026.6.0-dev 2026-05-14 12:33:43 +12:00
Jonathan Swoboda
a3b6f92433 [espidf] Regenerate bundled CMakeLists; auto-REQUIRE via IDF build properties (#16406) 2026-05-13 23:58:48 +00:00
dependabot[bot]
06786da7dd Bump actions/create-github-app-token from 3.1.1 to 3.2.0 (#16409)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-13 16:28:47 -07:00
Jonathan Swoboda
910cc38dd7 [writer] Clean ESP-IDF build artifacts in clean_build (#16410) 2026-05-13 19:25:35 -04:00
dependabot[bot]
c8aba6913b Bump requests from 2.34.0 to 2.34.1 (#16408)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-13 15:38:13 -05:00
Boris Krivonog
ce8810bc42 [mitsubishi_cn105] Add vane and wide-vane support (#16405) 2026-05-13 13:25:32 -05:00
Jonathan Swoboda
1c6966b761 [espidf] Run PIO extraScript with SCons-env shim (#16404) 2026-05-13 13:07:59 -04:00
J. Nick Koston
03f5e4775c [tests] Add CodSpeed benchmark for compiled-config cache fast path (#16402)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-13 12:06:20 -05:00
Boris Krivonog
445d841229 [mitsubishi_cn105] Simplified protocol lookups (#16399) 2026-05-13 16:49:32 +00:00
Jonathan Swoboda
d7b00047bd [espidf] Emit -W warning flags at project scope so managed components also see them (#16403) 2026-05-13 12:27:06 -04:00
Jonathan Swoboda
3fee97ae5a [espidf] Partition pio_components cache by framework (#16401) 2026-05-13 12:08:51 -04:00
J. Nick Koston
cb520cda6b [core] Retry PlatformIO downloads on transport-layer errors (#16397) 2026-05-13 10:01:42 -05:00
J. Nick Koston
8bce32ec35 [tests] Cover top-level !include failure path in track_yaml_loads (#16396) 2026-05-13 10:01:26 -05:00
J. Nick Koston
b866525437 [ci] Skip native ESP-IDF compile test when no relevant files changed (#16395) 2026-05-13 10:01:11 -05:00
J. Nick Koston
0e4922a340 [core] Cache validated config to skip re-validation on upload/logs (#16381) 2026-05-13 22:14:19 +12:00
Boris Krivonog
45a4811bb4 [mitsubishi_cn105] Unified timeout handling (#16385) 2026-05-13 01:40:19 -05:00
Dmitrii Kuminov
65ea29b44a [core] Fix !include vars not being substituted in !lambda values (#16320)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-12 22:41:30 -05:00
Keith Burzinski
480c23012c [radio_frequency] Add on_control trigger; ir_rf_proxy driver-agnostic (#16368)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 22:13:29 -05:00
Jonathan Swoboda
1dfd3fe9c2 [esp32] Print PlatformIO-format RAM/Flash summary after native ESP-IDF builds (#16394)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-12 22:52:11 -04:00
Michael Hansen
f94735dc62 [api][voice_assistant] Add second audio channel for voice_assistant (#16265)
Co-authored-by: Kevin Ahrendt <kevin.ahrendt@openhomefoundation.org>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2026-05-13 13:38:39 +12:00
Kevin Ahrendt
65b53692bd [i2s_audio] Properly track DMA input/output (#16317) 2026-05-12 20:36:26 -05:00
Kevin Ahrendt
3df0527c1f [audio] Document ring buffer source thread safety (#16393) 2026-05-13 00:10:32 +00:00
Mat931
dc95b22c76 [safe_mode] Allow recovering soft-bricked devices via reboot to recovery partition (#16339)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-13 12:07:49 +12:00
Jonathan Swoboda
1c2043e054 [esp32] Relax -Werror=reorder and -Werror=maybe-uninitialized on native ESP-IDF (#16392) 2026-05-12 20:04:54 -04:00
Kevin Ahrendt
7f37ee3c53 [mixer] Use RingBufferAudioSource (#16316) 2026-05-12 23:58:32 +00:00
Kevin Ahrendt
8b6cbc9f2b [i2s_audio] Speaker uses new RingBufferAudioSource (#16315)
Thanks!
2026-05-12 23:58:03 +00:00
George Galt
531367d7e1 [micro_wake_word] Increase INFERENCE_TASK_STACK_SIZE to 8192 for P4 chip (#16390) 2026-05-12 19:47:54 -04:00
Jesse Hills
cb2dbcd70d [ci] Add validate.*.yaml for config-only component tests (#16384) 2026-05-13 11:37:33 +12:00
Kevin Ahrendt
45a8bd49c3 [audio] Add a RingBufferAudioSource (#16314) 2026-05-12 19:33:03 -04:00
Jonathan Swoboda
9195b9898e [ms8607] Pin humidity i2c_id in test fixture (#16386) 2026-05-12 18:20:09 -05:00
dependabot[bot]
aec48cf231 Bump aioesphomeapi from 44.24.2 to 45.0.0 (#16391)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 23:19:07 +00:00
Jonathan Swoboda
907ae46aba [zigbee] Fix init-order and missing-field warnings on native ESP-IDF (#16389) 2026-05-12 19:13:04 -04:00
Jesse Hills
057fc4c1a8 Move AI instructions to AGENTS.md (#16382) 2026-05-13 09:19:27 +12:00
Cody Cutrer
76d3433425 [cli] Add config-hash command (#15548)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-12 20:43:48 +00:00
Kevin Ahrendt
b512cc42a8 [sendspin] Updates sendspin-cpp to v0.5.0 (#16380) 2026-05-12 16:42:44 -04:00
Boris Krivonog
66e4a1dfa8 [mitsubishi_cn105] Add C++ API for setting/clearing remote room temperature (#15558)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-12 15:39:21 -05:00
Kevin Ahrendt
ee72efa760 [sendspin] Fix client_id MAC mismatch with ethernet (#16331) 2026-05-12 16:27:25 -04:00
J. Nick Koston
f54480ec48 [rp2040] Bump arduino-pico framework to 5.6.0 (#16375) 2026-05-12 15:20:25 -05:00
J. Nick Koston
34f69e0d6e [ci] Comment on PRs that touch the legacy dashboard (#16378) 2026-05-12 14:42:23 -05:00
dependabot[bot]
57893a8eb1 Bump aioesphomeapi from 44.23.0 to 44.24.2 (#16376)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 19:37:31 +00:00
tomaszduda23
c511dddf2a [core] allow defining run_compile in external_components (#16179)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-12 14:59:54 -04:00
Jesse Hills
76ce45c59e [script] Preserve source order of enum options in language schema (#16371) 2026-05-13 06:28:39 +12:00
J. Nick Koston
727c74da3f [script] Fix array-type parameters in script.execute (#16374) 2026-05-12 12:17:23 -05:00
Jonathan Swoboda
365ed19319 [core] Fix PROGMEM_STRING_TABLE placement on ESP8266 without flash log strings (#16373) 2026-05-12 11:19:10 -04:00
Clyde Stubbs
4ff946ac15 [cli] Add --no-states flag to run command (#16366) 2026-05-12 07:52:07 -04:00
Mat931
b5e50144e3 [ota] Improve OTA error messages (#16327)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-05-12 02:32:58 +00:00
dependabot[bot]
49df1bd30e Bump actions/cache from 5.0.3 to 5.0.5 (#16365)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 02:18:06 +00:00
dependabot[bot]
7dce58c58d Bump requests from 2.33.1 to 2.34.0 (#16364)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 02:17:42 +00:00
Clyde Stubbs
a232aedebd [lvgl] Check for user defined LV_USE items (#16362) 2026-05-12 12:09:42 +10:00
Clyde Stubbs
4e31b71304 [lvgl] Add new trigger on_update and new number option (#16312) 2026-05-12 08:52:33 +10:00
J. Nick Koston
55ef66cc26 [helpers] Re-enable ProgressBar under --dashboard mode (#16357) 2026-05-11 13:12:55 -05:00
luar123
e479e8b641 [zigbee] Add power_source option to esp32 (#16062)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-11 14:08:52 -04:00
luar123
ee8ca2a3bf [zigbee] add on_join trigger for esp32 (#16060)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-11 11:54:35 -04:00
J. Nick Koston
a52ca4f80a [ota] Implement host platform OTA backend with re-exec for integration testing (#16304) 2026-05-11 10:51:08 -05:00
luar123
4ac7bc4606 [zigbee] Add sensor support on esp32 (#16026) 2026-05-11 10:51:47 -04:00
tomaszduda23
8cf0eba043 [nrf52][zephyr] prepare for native builds (#16193)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-11 14:47:06 +00:00
Keith Burzinski
30e2f7e8e9 [thermostat] Fix supplemental action never firing via max run time (#16308) 2026-05-11 10:13:43 -04:00
@RubenKelevra
a7299cb95b [esp32_camera] Downgrade esp32-camera to 2.1.5 (#16293) 2026-05-11 10:09:15 -04:00
tomaszduda23
2edb7ca5c2 [nrf52] add message that west update is running (#16321) 2026-05-11 10:05:41 -04:00
tomaszduda23
68534ea24d [logger] fix crash on zephyr (#16330) 2026-05-11 10:04:48 -04:00
rwrozelle
105842366e [openthread] Remove-freertos-portmacro-header-include (#16338) 2026-05-11 09:57:01 -04:00
J. Nick Koston
4d9d6e02e5 [core] Add stable esphome.upload_targets module for port classification (#16346) 2026-05-11 09:13:16 -04:00
J. Nick Koston
b967adeb9d [wifi] Accept lowercase variant in variant_has_wifi (#16345) 2026-05-11 09:11:36 -04:00
Jonathan Swoboda
e4d9786f00 [core] Move platformio files to subfolder (#16347) 2026-05-11 21:34:47 +12:00
Samuel Sieb
267836d098 [tuya] allow status pin that doesn't match the reported one (#16353) 2026-05-11 01:27:07 -07:00
Jesse Hills
c82adc3892 [ci] Fix external-component-bot 403 on PR comments (#16354) 2026-05-11 19:52:39 +12:00
Jesse Hills
fe66f9ba41 [ci] Tighten workflow permissions to least-privilege (#16349) 2026-05-11 17:15:53 +12:00
Jesse Hills
5dadfe6367 [ci] codeowner-review-request: mint least-privilege App token (#16351) 2026-05-11 17:04:09 +12:00
Jesse Hills
c4e85fbfc1 [ci] sync-device-classes: mint least-privilege App token (#16350) 2026-05-11 16:57:10 +12:00
Diorcet Yann
e9cc10fedc [core] Native idf full support (#14678)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <swoboda1337@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2026-05-11 02:12:07 +00:00
J. Nick Koston
66e2dcffc4 [cli] Tighten command_rename: scoped name rewrite, target-collision check (#16296) 2026-05-11 13:00:09 +12:00
J. Nick Koston
17080ddce6 [wifi][rp2040] Add stable wifi-capability helpers for device-builder (#16300) 2026-05-11 12:56:56 +12:00
J. Nick Koston
930d539969 [config_validation] Add a visibility UI-hint kwarg (#16267) 2026-05-11 12:07:15 +12:00
Clyde Stubbs
3c042e2e44 [lvgl] Ensure that on_value events fire on checked change (#16119) 2026-05-11 11:58:18 +12:00
Jesse Hills
ed10fbea3e [docker] Silence CopyIgnoredFile warning for build context root (#16311) 2026-05-11 07:25:49 +12:00
Mat931
1365251365 [ota] Add bootloader update functionality to ota component (#16238)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-08 21:36:06 +00:00
rwrozelle
3abf2c99a2 [openthread] add coroutine-with-priority COMMUNICATION (#16318) 2026-05-08 16:35:47 -05:00
Kevin Ahrendt
70b9edfabe [i2s_audio] Refactor SPDIF output, fixing synchronization problems (#16319) 2026-05-08 21:26:09 +00:00
John Boiles
88c2a1c096 [speaker] Add SPDIF output support (#8065)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Kevin Ahrendt <kevin.ahrendt@openhomefoundation.org>
2026-05-08 14:43:55 -04:00
Mat931
3d8fffbea9 [htu31d][kamstrup_kmp][ms8607] Use CRC functions from helpers.h (#16313) 2026-05-08 09:17:14 -04:00
Jonathan Swoboda
eb52ca61fe [climate][ektf2232] Remove deprecations scheduled for 2026.5.0 (#16289) 2026-05-08 07:26:14 -04:00
Jonathan Swoboda
a970f05b69 [clang-tidy] Enable readability-redundant-string-init (#16310) 2026-05-08 07:26:03 -04:00
Clyde Stubbs
7b6e2589f1 [modbus_server] Reduce log spam (#16283) 2026-05-08 14:09:22 +10:00
Jonathan Swoboda
696a654733 [clang-tidy] Concatenate nested namespaces (7/7: tests, platform-gated, enable check) (#16307) 2026-05-07 23:05:17 -04:00
Kevin Ahrendt
08b17c9da1 [core] Move core ring buffer to helper component (#16298) 2026-05-08 14:01:37 +12:00
Jesse Hills
e152c6155b [ci] Skip needs-docs for new components without CONFIG_SCHEMA (#16303) 2026-05-08 14:00:50 +12:00
Jonathan Swoboda
6ffcb821ca [clang-tidy] Concatenate nested namespaces (6/7: components t-z) (#16305) 2026-05-08 01:13:38 +00:00
Jonathan Swoboda
ded83812f4 [clang-tidy] Concatenate nested namespaces (5/7: components s) (#16302) 2026-05-08 00:16:51 +00:00
Jonathan Swoboda
ab1d2de78e [clang-tidy] Concatenate nested namespaces (4/7: components n-r) (#16301) 2026-05-07 23:28:30 +00:00
Jonathan Swoboda
cbe192df49 [clang-tidy] Concatenate nested namespaces (3/7: components i-m) (#16297) 2026-05-07 19:00:17 -04:00
dependabot[bot]
56ef357162 Bump github/codeql-action from 4.35.3 to 4.35.4 (#16299)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-07 17:51:30 -05:00
Jonathan Swoboda
4e4e4b4411 [clang-tidy] Concatenate nested namespaces (2/7: components d-h) (#16295) 2026-05-07 16:49:55 -04:00
Jonathan Swoboda
06bd92c388 [clang-tidy] Concatenate nested namespaces (1/7: components a-c) (#16294) 2026-05-07 14:21:39 -04:00
J. Nick Koston
71193e2b2c [helpers] Document write_file's external consumer contract (esphome-device-builder) (#16290) 2026-05-07 13:21:35 -05:00
Clyde Stubbs
9301f76482 [sensor] Add alternate calibration format for ntc (#15937) 2026-05-07 06:59:22 +10:00
Clyde Stubbs
004aa49131 [lvgl] Pass touch point to touch event lambdas (#16272) 2026-05-07 06:57:53 +10:00
dependabot[bot]
3b6250bcee Bump CodSpeedHQ/action from 4.15.0 to 4.15.1 (#16281)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-06 15:23:58 -05:00
Jesse Hills
a7b4a2006a Merge branch 'release' into dev 2026-05-07 08:13:00 +12:00
Jesse Hills
09dc41435c Merge pull request #16282 from esphome/bump-2026.4.5
2026.4.5
2026-05-07 08:12:15 +12:00
Jesse Hills
5283cdec12 Bump version to 2026.4.5 2026-05-07 07:25:35 +12:00
Edward Firmo
d9835c8705 [nextion] Fix text sensor state not updated on string response (#16280) 2026-05-07 07:25:35 +12:00
Mat931
b89c71c1ea [core] Fix WiFi connection in safe mode (#16269)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-05-07 07:25:35 +12:00
J. Nick Koston
7f6aef4f33 [substitutions] Fix sibling references inside dict-valued substitutions (#16273) 2026-05-07 07:25:35 +12:00
J. Nick Koston
016b509b55 [bundle] Include secrets.yaml when !secret keys are quoted (#16271) 2026-05-07 07:25:35 +12:00
Jesse Hills
d2bbaeccf3 [ha-addon] Add opt-in toggle for the new ESPHome Device Builder (#16247) 2026-05-07 07:25:35 +12:00
puddly
1e58e8729a [uart] Use tcdrain for flushing instead oftcflush on host (#14877)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-06 18:53:48 +00:00
J. Nick Koston
6173656bf8 [schema] Surface OnlyWith / OnlyWithout default + gate components in schema generator (#16276) 2026-05-06 13:49:00 -04:00
dbl-0
0d94ffe15d [resolver] Make RESOLVE_TIMEOUT configurable via environment variable (#15951)
Co-authored-by: Daniel Lowe <dan@auth.dxj.app>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-06 17:48:38 +00:00
Edward Firmo
4da62067cf [nextion] Fix text sensor state not updated on string response (#16280) 2026-05-06 13:32:50 -04:00
Kevin Ahrendt
9f49e3f80e [audio] Bump microFLAC to v0.2.0 (#16279) 2026-05-06 17:22:18 +00:00
Kevin Ahrendt
fc25ab0246 [i2s_audio] Optimize software volume control (#16278) 2026-05-06 12:57:03 -04:00
Kevin Ahrendt
a4a57a540d [core] Adds acquire and release methods to the ring buffer class (#16277) 2026-05-06 12:56:54 -04:00
Didier A
cfd2c9182c [bl0942] Remove broken 24-bit overflow tracking (#15650)
Co-authored-by: DidierA <1620015+didiera@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-06 12:34:55 -04:00
Mat931
2864922ac0 [ota] Partition table update: Fix log messages (#16241)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-06 09:59:10 -05:00
Mat931
90693fb39a [core] Fix WiFi connection in safe mode (#16269)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-05-06 09:56:33 -05:00
J. Nick Koston
6e1a59da3e [packages] Make package !include vars visible to its substitutions block (#16274) 2026-05-06 09:53:14 -05:00
John
545ee03f42 [atm90e32] Fix calibration instance not saving in flash properly (#14152)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-06 10:15:04 -04:00
J. Nick Koston
caaa1aefc7 [substitutions] Fix sibling references inside dict-valued substitutions (#16273) 2026-05-06 08:41:17 -05:00
J. Nick Koston
ff0c5f575e [bundle] Include secrets.yaml when !secret keys are quoted (#16271) 2026-05-06 07:32:35 -05:00
J. Nick Koston
f06ad8c436 [http_request] Add regression test for light action inside on_response (#16270) 2026-05-06 07:32:19 -05:00
Jonathan Swoboda
29db5fa4bb [script] Make pre-commit and helpers work on Windows (#16260)
Co-authored-by: Jonathan Swoboda <swoboda1337@users.noreply.github.com>
2026-05-06 07:11:06 -05:00
J. Nick Koston
85f33978e7 [core] Skip external component update on esphome clean (#16268) 2026-05-06 07:23:35 -04:00
Clyde Stubbs
79786f1cc7 [lvgl] Allow line points as percentages (#16209) 2026-05-06 07:22:43 -04:00
Kevin Ahrendt
febf8815c7 [audio_file][speaker] Eliminate code duplication for files built into firmware (#16266) 2026-05-06 05:59:51 -04:00
Jesse Hills
6f6d991dd2 [ha-addon] Add opt-in toggle for the new ESPHome Device Builder (#16247) 2026-05-06 21:42:11 +12:00
tomaszduda23
e9f7579910 [logger] give a chance to print crash (#16203)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-05-06 01:37:40 +00:00
tomaszduda23
a99c1b3e08 [nrf52] add reserve area for bootloader (#16204) 2026-05-05 20:37:03 -04:00
Kevin Ahrendt
2d6af1f7e5 [audio] Bump esp-audio-libs to v3.0.0 (#16263) 2026-05-05 20:22:53 -04:00
J. Nick Koston
700676b340 [api] Use entity_types.h X-macro for InitialStateIterator declarations (#16075) 2026-05-05 18:29:48 -05:00
J. Nick Koston
bf1c339dc1 [api] Use entity_types.h X-macro for ListEntitiesIterator declarations (#16076) 2026-05-05 18:29:32 -05:00
J. Nick Koston
f5c1b8839d [web_server] Use entity_types.h X-macro for ListEntitiesIterator declarations (#16077) 2026-05-05 18:29:10 -05:00
J. Nick Koston
4404dd68ba [cover] Fix ControlAction / CoverPublishAction trigger args with reference types (#16227) 2026-05-05 18:27:18 -05:00
J. Nick Koston
67491c3194 [packages] Add resolve_packages single-call seam (#16235) 2026-05-05 18:26:52 -05:00
J. Nick Koston
39b2b901f7 [core] Replace scheduler pool vector with unbounded intrusive freelist (#16172) 2026-05-05 18:26:19 -05:00
J. Nick Koston
f30ad588ea [cli] Add --ota-platform flag to pick web_server or native API OTA (#16207) 2026-05-05 18:25:53 -05:00
tomaszduda23
be82e8faeb [debug] Remove unused buffer in uicr lambda function (#16208) 2026-05-05 19:02:26 -04:00
Kevin Ahrendt
57397a318a [audio] Use the microWAV library for decoding (#16251) 2026-05-05 11:21:02 -05:00
Kevin Ahrendt
87a705b1cc [audio] Bump microOpus to v0.4.1 (#16255) 2026-05-05 12:47:07 +00:00
Keith Burzinski
edbb9f7b28 [i2s_audio] Fix stereo playback when slot bit width exceeds data bit width (#16248) 2026-05-05 08:15:32 -04:00
Jesse Hills
efff8fe8be [platformio_api] Remove duplicated _strip_win_long_path_prefix (#16249) 2026-05-05 14:29:23 +12:00
Jesse Hills
f248302370 Merge branch 'release' into dev 2026-05-05 14:22:23 +12:00
Jesse Hills
6fda5f41b2 Merge pull request #16240 from esphome/bump-2026.4.4
2026.4.4
2026-05-05 14:21:38 +12:00
Kevin Ahrendt
ea2b2b3920 [audio_file] Use microDecoder library instead of manual task management/decoding (#16237) 2026-05-04 20:12:26 -05:00
Kevin Ahrendt
f33d137669 [audio][media_player][speaker] WAV decoding is no longer always built (#16244) 2026-05-04 23:45:11 +00:00
dependabot[bot]
d28498ac2c Bump cryptography from 47.0.0 to 48.0.0 (#16245)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-04 23:39:44 +00:00
Olivier ARCHER
556783b95b [http_request] remove slow http_request warning on 8266 (#16239) 2026-05-04 18:19:52 -05:00
Kevin Ahrendt
857e529803 [audio] Use the microMP3 library instead of esp-audio-libs (#16236) 2026-05-04 18:41:50 -04:00
Jesse Hills
197d4dac8e Bump version to 2026.4.4 2026-05-05 08:27:10 +12:00
Jesse Hills
2d7f9dc48d [api] Use safe_print for log output and fix safe_print bytes-repr fallback (#16160) 2026-05-05 08:27:04 +12:00
J. Nick Koston
be84e6c9f4 [api] Fall back to owning types for service array args used after a delay (#16140) 2026-05-05 08:22:05 +12:00
J. Nick Koston
0418f2138a [esp32] Drop printf wrap on IDF 6.0+ (picolibc no longer needs it) (#16189) 2026-05-05 08:22:05 +12:00
Clyde Stubbs
d9c22d6b56 [lvgl] Clamp values for meter line indicators (#16180) 2026-05-05 08:22:05 +12:00
J. Nick Koston
60a94fd109 [esp32] Replace 512B stack buffer in printf wraps with picolibc cookie FILE (#16170) 2026-05-05 08:22:05 +12:00
Jesse Hills
9371ec319a [core] Strip \\?\ prefix from sys.executable for PlatformIO subprocess (#16158) 2026-05-05 08:21:58 +12:00
J. Nick Koston
ce466c6b60 [mcp23xxx_base] Reject unsupported interrupt_pin options (inverted, allow_other_uses) (#16149) 2026-05-05 08:14:03 +12:00
Brandon Harvey
a460f5343c [automation] Fix codegen type for component.resume update_interval (#16069)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 08:14:02 +12:00
Jesse Hills
7c2a63bf82 [api] Use safe_print for log output and fix safe_print bytes-repr fallback (#16160) 2026-05-05 08:12:20 +12:00
Diorcet Yann
690a197346 [main] Move stacktrace handling out of platformio_api and FlashImage into platform components/util (#16186) 2026-05-04 15:07:31 -04:00
J. Nick Koston
24d4da1021 [sensor] Document why TimeoutFilterBase intentionally keeps Component (#16194)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-04 01:18:28 +00:00
J. Nick Koston
53c4e6f386 [tests] Drop duplicate on_boot_restore_from in host_mode_climate_basic_state (#16228) 2026-05-03 20:12:51 -05:00
J. Nick Koston
1d63158480 [zephyr] Add nRF52 component tests so CI runs on zephyr-only changes (#16188) 2026-05-03 20:05:56 -05:00
J. Nick Koston
013dee44eb [binary_sensor] Drop Component from AutorepeatFilter, use self-keyed scheduler (#16191) 2026-05-03 20:05:27 -05:00
J. Nick Koston
9ddb828da3 [api] Don't tear down log connection on stack-trace decode failure (#16196) 2026-05-03 20:05:13 -05:00
J. Nick Koston
120d1e51fb [tests] Fix flaky host_mode_climate_basic_state integration test (#16192) 2026-05-03 20:04:34 -05:00
J. Nick Koston
844a36f7a1 [api] Mark high-volume proxy messages as speed_optimized (Infrared/RF, Z-Wave, serial) (#16159) 2026-05-03 20:03:52 -05:00
J. Nick Koston
72a75f2d3f [cover] Fold ControlAction/CoverPublishAction fields into stateless lambdas (#16046) 2026-05-03 20:02:07 -05:00
J. Nick Koston
b5eb444015 [dashboard] Stabilize device-builder dashboard backend's API surface (#16206)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-03 20:01:51 -05:00
J. Nick Koston
15ab5422c7 [ci] Run downstream device-builder tests against PR Python code (#16214) 2026-05-03 19:45:08 -05:00
J. Nick Koston
33f88619da [valve] Fix ControlAction trigger args with reference types (#16223) 2026-05-03 19:44:21 -05:00
J. Nick Koston
df1200629f [tests] Fix flaky host_mode_climate_basic_state (#16225) 2026-05-03 19:44:11 -05:00
J. Nick Koston
41bd570d30 [light] Fix LightControlAction trigger args with reference types (#16220) 2026-05-03 19:44:01 -05:00
J. Nick Koston
cf223674e5 [climate] Fix ControlAction trigger args with reference types (#16221) 2026-05-03 19:43:49 -05:00
J. Nick Koston
af74b639cf [fan] Fix TurnOnAction trigger args with reference types (#16222) 2026-05-03 19:43:35 -05:00
J. Nick Koston
4108b27197 [esp8266] Lower WDT_FEED_INTERVAL_MS to 100 ms (#16197) 2026-05-03 19:43:09 -05:00
Mat931
7cfab58a05 [ota] Add partition table update functionality to ota component (#15780)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-05-03 19:42:10 -05:00
tomaszduda23
85e1e4b95e [zephyr] feed watchdog early. Otherwise OTA may rollback. (#16218) 2026-05-03 20:37:32 -04:00
J. Nick Koston
0f174ee626 [api] Fall back to owning types for service array args used after a delay (#16140) 2026-05-04 10:55:40 +12:00
Edward Firmo
8046ff7e1e [nextion] TFT upload no longer fails when the display sends a split 0x08 ack (#16205)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-05-03 03:40:09 -05:00
dependabot[bot]
5e9db1c8c6 Bump github/codeql-action from 4.35.2 to 4.35.3 (#16201)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 21:46:29 -05:00
J. Nick Koston
81d147ff9e [esp32] Drop printf wrap on IDF 6.0+ (picolibc no longer needs it) (#16189) 2026-05-01 14:31:56 -05:00
Mat931
58cb7effd4 [ota] Add extended OTA protocol (#16164)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-05-01 10:40:14 -05:00
Kevin Ahrendt
3dd60c5713 [core] Support allocating ring buffer in internal memory (#16187) 2026-05-01 07:55:08 -05:00
Oliver Kleinecke
f073c1cabe [usb_host][usb_uart] Add configurable max packet size (#14584) 2026-05-01 20:43:13 +10:00
J. Nick Koston
5cc447e0da [core] Move per-platform hal_platform.h into components/platform/hal.h (#16183) 2026-04-30 21:27:31 -05:00
Clyde Stubbs
0980630f68 [lvgl] Clamp values for meter line indicators (#16180) 2026-04-30 22:23:14 -04:00
J. Nick Koston
b8dfffdf06 [core] Enable ruff FLY (flynt) lint family (#16182) 2026-04-30 21:20:07 -05:00
luar123
f6e39d305d [zigbee] Add newlib compatibility for zigbee sdk in idf 6 (#16174) 2026-04-30 22:08:55 -04:00
Jonathan Swoboda
08e5cb5576 [esp32_hosted] Bump esp_hosted to 2.12.6 and esp_wifi_remote to 1.5.1 (#16176) 2026-04-30 20:47:22 -05:00
Kevin Ahrendt
faa61696e0 [sendspin] Use sendspin-cpp to v0.4.0 to reduce stuttering (#16178) 2026-04-30 20:43:24 -05:00
J. Nick Koston
9999913d07 [zephyr] Move HAL bodies into components/zephyr/hal.cpp + inline trivial dispatches (#16116) 2026-04-30 20:10:51 -05:00
J. Nick Koston
92aa98f680 [host] Move HAL bodies into components/host/hal.cpp + inline trivial dispatches (#16115) 2026-05-01 00:42:38 +00:00
J. Nick Koston
3d69169141 [climate] Fold ControlAction fields into a single stateless lambda (#16044) 2026-04-30 19:16:16 -05:00
J. Nick Koston
24fdfcf1a1 [rp2040] Move HAL bodies into components/rp2040/hal.cpp + inline trivial dispatches (#16114) 2026-04-30 19:15:41 -05:00
J. Nick Koston
550444dc34 [binary_sensor] Drop Component from filter classes, use self-keyed scheduler (#16131) 2026-04-30 19:15:18 -05:00
J. Nick Koston
ba7c06785a [mdns] Broadcast config_hash TXT record on _esphomelib._tcp (#16145) 2026-04-30 19:14:55 -05:00
J. Nick Koston
b708d1a826 [core] Drop unused DELAY_ACTION from InternalSchedulerID enum (#16151) 2026-04-30 19:14:34 -05:00
J. Nick Koston
148d478dec [api] Add encode/decode benchmarks for Z-Wave, IR/RF, and serial proxy messages (#16157) 2026-04-30 19:14:20 -05:00
J. Nick Koston
45e78e4114 [core] Inline loop gate expression to avoid stale local reuse (#16167) 2026-04-30 19:13:54 -05:00
J. Nick Koston
3b3e003aa3 [sensor] Pack ThrottleAverageFilter have_nan_ into n_ bitfield (-4 B/instance) (#16169) 2026-04-30 19:13:10 -05:00
J. Nick Koston
2f3e16b482 [bk72xx] Apply CFG_SUPPORT_BLE=0 SDK option to BK7238 (#16181) 2026-04-30 19:12:06 -05:00
J. Nick Koston
e085cb50d9 [sensor] Drop Component from filter classes, use self-keyed scheduler (#16132) 2026-04-30 19:11:30 -05:00
J. Nick Koston
2fbfb4c385 [ci] Split integration tests into 3 buckets when count is more than 10 (#16152) 2026-04-30 19:10:53 -05:00
J. Nick Koston
61261b4a59 [libretiny] Move HAL bodies into components/libretiny/hal.cpp + inline trivial dispatches (#16113) 2026-04-30 12:33:22 -05:00
J. Nick Koston
d48aad8c4d [esp32] Replace 512B stack buffer in printf wraps with picolibc cookie FILE (#16170) 2026-04-30 13:27:54 -04:00
Kevin Ahrendt
f1d3be4bda [core] Simplify RAMAllocator and add internal fallback to external mode (#16171) 2026-04-30 12:03:40 -04:00
Kevin Ahrendt
2758aa5517 [audio] bump microOpus to v0.4.0 to use fixed-point by default on ESP32 (#16168) 2026-04-30 09:12:39 -04:00
Kevin Ahrendt
a8b0133ec1 [audio] Enable specific codecs and configure advanced features (#16166) 2026-04-30 08:49:28 -04:00
Clyde Stubbs
1398dcebb4 [st7789v] Add deprecation warnings (#16162) 2026-04-30 00:53:37 -05:00
dependabot[bot]
096d0c4279 Bump aioesphomeapi from 44.22.0 to 44.23.0 (#16161)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-30 04:45:19 +00:00
Jesse Hills
e127268dac [core] Strip \\?\ prefix from sys.executable for PlatformIO subprocess (#16158) 2026-04-30 16:04:52 +12:00
J. Nick Koston
f0bffed3c0 [esp8266] Move HAL bodies into components/esp8266/hal.cpp + inline arch_init (#16112) 2026-04-30 15:42:17 +12:00
Jesse Hills
1a871e231d [ci] Use client-id for GitHub App token generation (#16155) 2026-04-30 13:09:37 +12:00
Jesse Hills
47765bd2d0 [ci] Correct version comment on create-github-app-token pin (#16156) 2026-04-30 13:08:56 +12:00
dependabot[bot]
8066325e0b Bump esphome/workflows/.github/workflows/lock.yml from 2026.4.0 to 2026.4.1 (#16143)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-30 12:52:25 +12:00
J. Nick Koston
b8d24c9e49 [mcp23xxx_base] Reject unsupported interrupt_pin options (inverted, allow_other_uses) (#16149) 2026-04-30 11:14:07 +12:00
J. Nick Koston
9b1f5c59bb [core] Fix null deref in WarnIfComponentBlockingGuard for self-keyed scheduler timers (#16150) 2026-04-29 23:05:38 +00:00
Jonathan Swoboda
e4b33fddf5 [esp32] Add ESP-IDF 6.0.1 platform entry (#16146) 2026-04-29 18:43:15 -04:00
Jonathan Swoboda
77da64a367 [sx126x] Add cold sleep option and drop unused RTC wakeup bit (#16144) 2026-04-29 17:05:51 -04:00
J. Nick Koston
cecccebc64 [core] DelayAction: drop Component inheritance, use self-keyed scheduler (#16129) 2026-04-29 20:35:04 +00:00
Jonathan Swoboda
53b682e48f [ci] Bump clang-tidy from 18.1.8 to 22.1.0.1 (#16078)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-29 20:19:33 +00:00
Mat931
14910e65d9 [ota] Use WatchdogManager for OTA on ESP32 (#16138)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-04-29 20:15:21 +00:00
J. Nick Koston
813964714c [esp32] Move HAL bodies into components/esp32/hal.cpp + inline trivial dispatches (#16111) 2026-04-29 20:09:08 +00:00
J. Nick Koston
5a146ab6b7 [valve] Fold ControlAction fields into a single stateless lambda (#16123) 2026-04-29 19:20:15 +00:00
J. Nick Koston
61a41402df [fan] Fold TurnOnAction fields into a single stateless lambda (#16122) 2026-04-29 19:16:05 +00:00
Mat931
59b4cfd07c [watchdog] Use default CHECK_IDLE_TASK and PANIC when configuring the watchdog (#16142) 2026-04-29 18:41:12 +00:00
J. Nick Koston
c41f38e16d [scheduler] Add self-keyed timer API for callers without a Component (#16127) 2026-04-29 13:24:37 -05:00
Clyde Stubbs
0ad8a071a7 [espnow] Cleanup method visibility and naming (#16109) 2026-04-29 14:18:21 -04:00
J. Nick Koston
985dba9332 [core] Defer heavy module-scope imports in __main__, loader, and config (#15955) 2026-04-29 13:17:59 -05:00
GelidusResearch
ca3f7251d4 [ens160] Fix sensor initialization timing (#16024)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-29 14:07:28 -04:00
J. Nick Koston
44cabc191d [core] Catch body-read errors in download_content (#16023) 2026-04-29 14:06:41 -04:00
J. Nick Koston
e5b1991cf7 [fan] Add tests for fan.turn_on action field combinations (#16125) 2026-04-29 12:46:06 -05:00
J. Nick Koston
7fba57ce51 [valve] Add tests for valve.control action field combinations (#16126) 2026-04-29 12:45:30 -05:00
J. Nick Koston
69a33d8ac0 [core] Inline HAL clock wrappers and split hal.h into per-platform headers (#15977) 2026-04-29 12:31:55 -05:00
Jonathan Swoboda
ce61dcf387 [remote_base][core] Drop redundant typename in dependent type contexts (#16137) 2026-04-29 16:54:17 +00:00
Jonathan Swoboda
bae6b51652 [kamstrup_kmp][toshiba] Fix signed/unsigned comparisons against sizeof (#16135) 2026-04-29 11:33:57 -04:00
Jonathan Swoboda
557c3d4436 [aqi] Use std::max initializer-list for non-negative AQI clamp (#16134) 2026-04-29 11:33:29 -04:00
Jonathan Swoboda
bacee89bca [mixer_speaker] NOLINT bugprone-unchecked-optional-access in audio_mixer_task (#16130) 2026-04-29 10:56:13 -04:00
Jonathan Swoboda
2157d11913 [haier] Fix bugprone-unchecked-optional-access; switch HardwareInfo to char[9] (#16124) 2026-04-29 14:26:53 +00:00
Jonathan Swoboda
42b8597719 [api] Extend NOLINT to cover bugprone-random-generator-seed in MAC varint test (#16120) 2026-04-29 13:58:19 +00:00
Jonathan Swoboda
2bd28eee9d [tormatic] Use .value() for checked optional access in read_gate_status_ (#16121) 2026-04-29 09:51:31 -04:00
J. Nick Koston
0a497d3c22 [light] Fold LightControlAction fields into a single stateless lambda (#16118) 2026-04-29 08:35:17 -05:00
Jonathan Swoboda
79da2b9704 [time] Fix bugprone-unchecked-optional-access in CronTrigger::check_time_ (#16107) 2026-04-29 08:30:46 -04:00
Jonathan Swoboda
ae5b211c89 [api] Avoid JsonDocument copy-and-swap operator= in ActionResponse ctor (#16106) 2026-04-29 08:30:35 -04:00
J. Nick Koston
8ceada8d04 [core] Download external_files in parallel (#16021) 2026-04-29 14:32:30 +12:00
J. Nick Koston
49c7a6928e [script] Fix cpp_unit_test crash for non-MULTI_CONF platform components (#16104) 2026-04-29 14:32:13 +12:00
J. Nick Koston
2fce71e0d4 [wifi] Add phy_mode option for ESP8266 (#16055) 2026-04-29 14:31:07 +12:00
J. Nick Koston
80251c54be [climate] Add climate.control coverage to component tests via thermostat (#16052) 2026-04-29 14:27:56 +12:00
J. Nick Koston
0d51a122d0 [cover] Add cover.control / cover.template.publish coverage to template tests (#16051) 2026-04-29 14:27:40 +12:00
J. Nick Koston
5a33c50015 [light] Use constexpr template for DimRelativeAction transition_length (#16038) 2026-04-29 14:26:38 +12:00
J. Nick Koston
0d150dc57e [light] Use constexpr template for ToggleAction transition_length (#16037) 2026-04-29 14:25:18 +12:00
J. Nick Koston
d287876d8d [light] Use bitmask template for LightControlAction unused fields (#16039) 2026-04-29 14:20:37 +12:00
J. Nick Koston
592486ae9a [analyze_memory] Attribute main.cpp setup()/loop() to esphome core (#16033) 2026-04-29 14:06:54 +12:00
Jonathan Swoboda
c3bd38af77 [feedback] Fix bugprone-unchecked-optional-access in start_direction_ (#16103) 2026-04-28 21:54:15 -04:00
J. Nick Koston
eec770d622 [core] Use ETag in external_files cache to fix re-downloads from raw.githubusercontent.com (#16020) 2026-04-29 13:52:09 +12:00
J. Nick Koston
d7b21a84a3 [git] Make ref fetches and submodule updates shallow (#16014) 2026-04-29 13:49:51 +12:00
J. Nick Koston
f05243bd9d [api] Add 48-bit MAC address varint fast path for BLE advertisements (#15988) 2026-04-29 13:48:35 +12:00
J. Nick Koston
35cb28edfe [output] Gate FloatOutput power scaling fields behind USE_OUTPUT_FLOAT_POWER_SCALING (#15998) 2026-04-29 13:27:22 +12:00
J. Nick Koston
1363f661e6 [core] Inline ContinuationAction in If/While/RepeatAction (#16040) 2026-04-28 21:26:25 -04:00
J. Nick Koston
8af499b591 [api] Use custom deleter to fix incomplete-type error on macOS libc++ (#16050) 2026-04-28 21:26:21 -04:00
Jonathan Swoboda
1a57d9bc2f [sprinkler][pn532] Fix bugprone-unchecked-optional-access (#16102) 2026-04-29 01:04:19 +00:00
J. Nick Koston
9768380856 [api] Hoist memw out of socket ready check to once per main-loop iter (#15996) 2026-04-29 13:04:10 +12:00
J. Nick Koston
676f26919e [mdns] Drive MDNS.update() polling from IP state events on ESP8266/RP2040 (#15961) 2026-04-29 13:02:21 +12:00
J. Nick Koston
29d3a3a498 [esp8266] Replace millis() with fast accumulator, wrap Arduino callers (#15662) 2026-04-29 12:58:00 +12:00
Jonathan Swoboda
77b76ac48a [inkbird_ibsth1_mini][speaker][speaker_source] Fix performance-unnecessary-copy-initialization (#16101) 2026-04-29 00:56:03 +00:00
Clyde Stubbs
0b5835284a [lvgl] Additional layout features (#16041) 2026-04-29 12:35:24 +12:00
Jonathan Swoboda
15df477472 [core] Reduce copies in Callback/CallbackManager call paths (#16093)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-04-28 19:41:28 -04:00
Jonathan Swoboda
be0ee73847 [i2c] NOLINT readability-identifier-naming on Zephyr struct forward-decl (#16099) 2026-04-28 19:22:42 -04:00
Jonathan Swoboda
a241c9e622 [online_image][sim800l] Use std::string::starts_with for prefix checks (#16097) 2026-04-28 19:02:39 -04:00
Jonathan Swoboda
2f433c78bd [haier] Brace single-statement else-if in smartair2_climate (#16098) 2026-04-28 18:56:36 -04:00
Jonathan Swoboda
e39c474577 [binary_sensor] Bind at_index_ once in MultiClick on_state_ (#16095) 2026-04-28 22:13:35 +00:00
Jonathan Swoboda
a62e3fe4fc [json] NOLINT StackAddressEscape false positive in parse_json (#16091) 2026-04-28 21:35:40 +00:00
Jonathan Swoboda
7d6b9bee19 [wifi] Avoid copying EAP config in three connect handlers (#16094) 2026-04-28 21:22:29 +00:00
Jonathan Swoboda
ab6bda50e4 [esp32_ble] Widen loop variable in as_128bit() to match uuid_.len type (#16088) 2026-04-28 20:58:40 +00:00
Jonathan Swoboda
3d195d748c [ezo] Use make_unique to construct EzoCommand (#16092) 2026-04-28 20:50:15 +00:00
Jonathan Swoboda
16cf4fb5e8 [nextion] Use std::string::starts_with for HTTPS URL check (#16090) 2026-04-28 20:47:20 +00:00
Jonathan Swoboda
70503442f4 [dfrobot_sen0395] Brace single-statement else-if in enqueue() (#16089) 2026-04-28 20:37:29 +00:00
Jonathan Swoboda
594b269dba [bme680] Rename cal1/cal2 to coeff1/coeff2 (#16087) 2026-04-28 20:33:57 +00:00
Clyde Stubbs
8157c721a5 [mapping] Implement default value (#15861) 2026-04-29 06:31:37 +10:00
Clyde Stubbs
9af557de6d [lvgl] Add utility gradient function (#16048) 2026-04-29 06:29:38 +10:00
Jonathan Swoboda
1f4136e76f [pipsolar] Guard handle_qmod_ against empty message (#16085) 2026-04-28 16:29:09 -04:00
Jonathan Swoboda
c8dffcc9b8 [tlc5971] Remove dead bit-banging delay code (#16086) 2026-04-28 15:28:33 -05:00
dependabot[bot]
44fbb7f5a9 Bump CodSpeedHQ/action from 4.14.0 to 4.15.0 (#16084)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-28 15:10:21 -05:00
Jonathan Swoboda
eb01d43feb [spi][http_request][demo] Fix latent clang-tidy issues in headers (#16080) 2026-04-28 16:09:35 -04:00
Jonathan Swoboda
7891fd5cf1 Add dependencies.lock to .gitignore (#16081) 2026-04-29 07:38:31 +12:00
Jonathan Swoboda
4ee9cc432b [ci] Install requirements_dev.txt in the cached venv (#16082) 2026-04-29 07:37:46 +12:00
Mat931
42ff10afe5 [watchdog] Fix WatchdogManager on single core apps (#16074) 2026-04-28 17:32:44 +00:00
tomaszduda23
6b3df66bdc [nrf52] make reset pin optional (#11684)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-04-28 12:20:38 -05:00
tomaszduda23
968878a62d [nrf52] implement wake_loop_threadsafe/wakeable_delay (#16032)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-28 16:35:12 +00:00
J. Nick Koston
daf3f4d2f1 [core] wakeable_delay: yield on already-woken fast path (ESP8266, RP2040) (#16045) 2026-04-28 10:41:17 -05:00
Bonne Eggleston
52e8c50f45 [modbus] Split modbus_server from modbus_controller (#15509)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-04-28 10:21:25 -05:00
J. Nick Koston
0a4d9b430f [ci] Add import-time regression check for esphome.__main__ (#15954) 2026-04-28 14:05:12 +00:00
J. Nick Koston
0759a3c681 [core] Split wake.{h,cpp} into per-platform files (#15978) 2026-04-28 08:48:13 -05:00
Egor Vorontsov
8921e3bb3f [api] add open states for lock to api.proto (#15901)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-04-28 07:49:16 -05:00
Clyde Stubbs
52f80618d4 [lvgl] Allow a binary sensor to report checked or pressed state (#16073)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-04-28 22:00:29 +10:00
Jesse Hills
876c8c4c2a [ci-custom] Lint imports of esphome.components.const outside components (#16068)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 05:59:02 -05:00
Darafei Praliaskouski
41458d72e0 [esp32] Make Arduino app metadata reproducible (#16053) 2026-04-28 05:58:34 -05:00
Brandon Harvey
49d3df2698 [automation] Fix codegen type for component.resume update_interval (#16069)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 05:27:20 -05:00
J. Nick Koston
792f2e8363 [ota] Add wall-clock timeout to OTA data transfer loop (#16047) 2026-04-28 17:29:42 +12:00
J. Nick Koston
42c9fdc87e [feedback] Use App.get_loop_component_start_time() and constexpr timeout id (#16063) 2026-04-28 16:39:08 +12:00
Jesse Hills
5f6bbb98ce Merge branch 'release' into dev 2026-04-28 15:40:19 +12:00
Jesse Hills
4e0509435a Merge pull request #16067 from esphome/bump-2026.4.3
2026.4.3
2026-04-28 15:39:24 +12:00
J. Nick Koston
a03de7cea2 [core] Freshen loop_component_start_time_ before scheduler dispatch (#16064) 2026-04-28 13:23:08 +12:00
Jesse Hills
95b5ab7e78 Bump version to 2026.4.3 2026-04-28 12:58:29 +12:00
J. Nick Koston
3ac0939f55 [image] Fix RGB565+alpha rendering for multi-frame animations (#16017)
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-28 12:58:29 +12:00
Jesse Hills
191d3bc7e4 [esp32_touch] Feed wdt (#16066) 2026-04-28 12:58:29 +12:00
Edward Firmo
a186f6fea9 [nextion] Unify TFT upload ack timeout to 5000ms (#15960) 2026-04-28 12:58:29 +12:00
Mat931
aea88aef5e [esp32][wifi] Fix bootloop and WiFi connection issue if nvs partition is missing or has non-default label (#16025)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-04-28 12:58:29 +12:00
J. Nick Koston
433bbdb016 [rotary_encoder][at581x] Fix templatable int field types (#16015) 2026-04-28 12:58:29 +12:00
J. Nick Koston
4137d93cbf [wifi] Fix stale wifi.connected after state transition (#15966) 2026-04-28 12:58:29 +12:00
J. Nick Koston
6a5919ee87 [deep_sleep] Fix sleep_duration codegen type to uint32_t (#15965) 2026-04-28 12:58:29 +12:00
Jesse Hills
b753ee4e94 [time] Handle Windows EINVAL when validating POSIX TZ strings (#15934) 2026-04-28 12:58:29 +12:00
Clyde Stubbs
c26ea52620 [lvgl] Triggers on tabview tabs fix (#15935) 2026-04-28 12:58:29 +12:00
J. Nick Koston
39a69385fb [image] Fix RGB565+alpha rendering for multi-frame animations (#16017)
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-28 12:57:42 +12:00
Jesse Hills
a34836c290 [esp32_touch] Feed wdt (#16066) 2026-04-28 11:27:08 +12:00
Edward Firmo
01ac223913 [nextion] Unify TFT upload ack timeout to 5000ms (#15960) 2026-04-28 08:30:40 +12:00
Mat931
7198c912c7 [esp32][wifi] Fix bootloop and WiFi connection issue if nvs partition is missing or has non-default label (#16025)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-04-27 12:41:28 -05:00
Kevin Ahrendt
24c6a0d711 [audio] Bump microDecoder library to v0.2.0 (#16054) 2026-04-27 12:17:02 +00:00
plazarre
dec5d0449b [esp32_ble_tracker] Hold COEX_PREFER_BT for the lifetime of any active connection (#16036)
Co-authored-by: Paul Lazarre <plazarre@gmail.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-04-27 06:51:54 -05:00
J. Nick Koston
79b741b8dc [core] Combine entity register + configure_entity_ into one call (#16030) 2026-04-27 03:03:39 +00:00
tomaszduda23
112646a9c4 [zigbee] add router for nrf52 (#16034) 2026-04-26 23:02:09 -04:00
J. Nick Koston
2e096bb036 [core] Combine set_component_source_ + register_component_ into one call (#16029) 2026-04-26 21:54:15 -05:00
2643 changed files with 56626 additions and 17284 deletions

View File

@@ -5,24 +5,30 @@ Checks: >-
-altera-*,
-android-*,
-boost-*,
-bugprone-derived-method-shadowing-base-method,
-bugprone-easily-swappable-parameters,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-invalid-enum-default-initialization,
-bugprone-multi-level-implicit-pointer-conversion,
-bugprone-narrowing-conversions,
-bugprone-tagged-union-member-count,
-bugprone-signed-char-misuse,
-bugprone-switch-missing-default-case,
-cert-dcl50-cpp,
-cert-err33-c,
-cert-err58-cpp,
-cert-int09-c,
-cert-oop57-cpp,
-cert-str34-c,
-clang-analyzer-optin.core.EnumCastOutOfRange,
-clang-analyzer-optin.cplusplus.UninitializedObject,
-clang-analyzer-osx.*,
-clang-analyzer-security.ArrayBound,
-clang-diagnostic-delete-abstract-non-virtual-dtor,
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
-clang-diagnostic-deprecated-declarations,
-clang-diagnostic-ignored-optimization-argument,
-clang-diagnostic-missing-designated-field-initializers,
-clang-diagnostic-missing-field-initializers,
-clang-diagnostic-shadow-field,
-clang-diagnostic-unused-const-variable,
@@ -42,6 +48,7 @@ Checks: >-
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-prefer-member-initializer,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-const-cast,
@@ -54,12 +61,13 @@ Checks: >-
-cppcoreguidelines-rvalue-reference-param-not-moved,
-cppcoreguidelines-special-member-functions,
-cppcoreguidelines-use-default-member-init,
-cppcoreguidelines-use-enum-class,
-cppcoreguidelines-virtual-class-destructor,
-fuchsia-default-arguments-calls,
-fuchsia-default-arguments-declarations,
-fuchsia-multiple-inheritance,
-fuchsia-overloaded-operator,
-fuchsia-statically-constructed-objects,
-fuchsia-default-arguments-declarations,
-fuchsia-default-arguments-calls,
-google-build-using-namespace,
-google-explicit-constructor,
-google-readability-braces-around-statements,
@@ -71,49 +79,63 @@ Checks: >-
-llvm-else-after-return,
-llvm-header-guard,
-llvm-include-order,
-llvm-prefer-static-over-anonymous-namespace,
-llvm-qualified-auto,
-llvm-use-ranges,
-llvmlibc-*,
-misc-const-correctness,
-misc-include-cleaner,
-misc-multiple-inheritance,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-override-with-different-visibility,
-misc-unused-parameters,
-misc-use-anonymous-namespace,
-misc-use-internal-linkage,
-modernize-avoid-bind,
-modernize-avoid-variadic-functions,
-modernize-avoid-c-arrays,
-modernize-concat-nested-namespaces,
-modernize-avoid-c-style-cast,
-modernize-macro-to-enum,
-modernize-return-braced-init-list,
-modernize-type-traits,
-modernize-use-auto,
-modernize-use-constraints,
-modernize-use-default-member-init,
-modernize-use-designated-initializers,
-modernize-use-equals-default,
-modernize-use-integer-sign-comparison,
-modernize-use-nodiscard,
-modernize-use-nullptr,
-modernize-use-nodiscard,
-modernize-use-nullptr,
-modernize-use-ranges,
-modernize-use-trailing-return-type,
-mpi-*,
-objc-*,
-performance-enum-size,
-portability-avoid-pragma-once,
-portability-template-virtual-member-function,
-readability-ambiguous-smartptr-reset-call,
-readability-avoid-nested-conditional-operator,
-readability-container-contains,
-readability-container-data-pointer,
-readability-convert-member-functions-to-static,
-readability-else-after-return,
-readability-enum-initial-value,
-readability-function-cognitive-complexity,
-readability-implicit-bool-conversion,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-make-member-function-const,
-readability-math-missing-parentheses,
-readability-named-parameter,
-readability-redundant-casting,
-readability-redundant-inline-specifier,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-redundant-parentheses,
-readability-redundant-typename,
-readability-uppercase-literal-suffix,
-readability-use-anyofallof,
-readability-use-std-min-max,
-readability-use-concise-preprocessor-directives,
WarningsAsErrors: '*'
FormatStyle: google
CheckOptions:

View File

@@ -1 +1 @@
1b1ce6324c50c4595703c7df0a8a479b4fe84b71ff1a8793cce1a16f17a33324
72f02816e288b68ff4ef4b3d6fb66432c893b187a80ad3ebaa29afa443ff9ea6

View File

@@ -29,7 +29,7 @@ Required fields:
- **What does this implement/fix?**: Brief description of changes
- **Types of changes**: Check ONE appropriate box (Bugfix, New feature, Breaking change, etc.)
- **Related issue**: Use `fixes <link>` syntax if applicable
- **Pull request in esphome-docs**: Link if docs are needed
- **Pull request in esphome.io**: Link if docs are needed
- **Test Environment**: Check platforms you tested on
- **Example config.yaml**: Include working example YAML
- **Checklist**: Verify code is tested and tests added
@@ -54,9 +54,9 @@ Required fields:
- fixes https://github.com/esphome/esphome/issues/XXX
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):**
**Pull request in [esphome.io](https://github.com/esphome/esphome.io) with documentation (if applicable):**
- esphome/esphome-docs#XXX
- esphome/esphome.io#XXX
## Test Environment
@@ -83,7 +83,7 @@ component_name:
- [x] Tests have been added to verify that the new code works (under `tests/` folder).
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
- [ ] Documentation added/updated in [esphome.io](https://github.com/esphome/esphome.io).
```
## 5. Push and Create PR

View File

@@ -115,4 +115,4 @@ examples/
Dockerfile
.git/
tests/
.*
.?*

View File

@@ -2,7 +2,7 @@
blank_issues_enabled: false
contact_links:
- name: Report an issue with the ESPHome documentation
url: https://github.com/esphome/esphome-docs/issues/new/choose
url: https://github.com/esphome/esphome.io/issues/new/choose
about: Report an issue with the ESPHome documentation.
- name: Report an issue with the ESPHome web server
url: https://github.com/esphome/esphome-webserver/issues/new/choose

View File

@@ -16,9 +16,9 @@
- fixes <link to issue>
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):**
**Pull request in [esphome.io](https://github.com/esphome/esphome.io) with documentation (if applicable):**
- esphome/esphome-docs#<esphome-docs PR number goes here>
- esphome/esphome.io#<esphome.io PR number goes here>
## Test Environment
@@ -43,4 +43,4 @@
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
- [ ] Documentation added/updated in [esphome.io](https://github.com/esphome/esphome.io).

View File

@@ -15,11 +15,6 @@ inputs:
description: "Version to build"
required: true
example: "2023.12.0"
base_os:
description: "Base OS to use"
required: false
default: "debian"
example: "debian"
runs:
using: "composite"
steps:
@@ -47,7 +42,7 @@ runs:
- name: Build and push to ghcr by digest
id: build-ghcr
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
@@ -60,7 +55,6 @@ runs:
build-args: |
BUILD_TYPE=${{ inputs.build_type }}
BUILD_VERSION=${{ inputs.version }}
BUILD_OS=${{ inputs.base_os }}
outputs: |
type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
@@ -73,7 +67,7 @@ runs:
- name: Build and push to dockerhub by digest
id: build-dockerhub
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
@@ -86,7 +80,6 @@ runs:
build-args: |
BUILD_TYPE=${{ inputs.build_type }}
BUILD_VERSION=${{ inputs.version }}
BUILD_OS=${{ inputs.base_os }}
outputs: |
type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true

View File

@@ -0,0 +1,46 @@
name: Cache ESP-IDF
description: >
Resolve the pinned ESP-IDF version and cache the native ESP-IDF install
(toolchains + source) at ~/.esphome-idf. Every job that installs ESP-IDF
natively (clang-tidy for IDF/Arduino and the native-IDF component build)
shares one cache, since the install is identical (ESPHOME_IDF_DEFAULT_TARGETS
defaults to "all", so all toolchains are present regardless of the chip).
Callers must set env ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf and have the
Python venv already restored.
inputs:
framework:
description: 'Which pinned IDF version to key on: "espidf" (recommended) or "arduino".'
default: espidf
runs:
using: composite
steps:
- name: Resolve ESP-IDF version for cache key
# The native-IDF version is pinned in code, not in any file that feeds the
# other cache keys, so resolve it explicitly. Keying on it means the cache
# invalidates on a version bump (actions/cache never overwrites a key).
id: version
shell: bash
run: |
. venv/bin/activate
if [ "${{ inputs.framework }}" = "arduino" ]; then
version=$(python -c 'from esphome.components.esp32 import ARDUINO_FRAMEWORK_VERSION_LOOKUP as A, ARDUINO_IDF_VERSION_LOOKUP as L; print(L[A["recommended"]])')
else
version=$(python -c 'from esphome.components.esp32 import ESP_IDF_FRAMEWORK_VERSION_LOOKUP as L; print(L["recommended"])')
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
# Mirror the adjacent PlatformIO cache: only dev-branch runs write the
# shared cache (so it lives in the default-branch scope readable by all
# PRs), and PRs are restore-only -- they never push multi-GB artifacts into
# their own scope / the repo quota (e.g. on a version-bump PR).
- name: Cache ESP-IDF install (write on dev)
if: github.ref == 'refs/heads/dev'
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.esphome-idf
key: ${{ runner.os }}-esphome-idf-${{ steps.version.outputs.version }}
- name: Cache ESP-IDF install (restore-only off dev)
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.esphome-idf
key: ${{ runner.os }}-esphome-idf-${{ steps.version.outputs.version }}

View File

@@ -27,6 +27,18 @@ runs:
path: venv
# yamllint disable-line rule:line-length
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ inputs.cache-key }}
- name: Set up uv
# Only needed on cache miss to populate the venv. ``uv pip install``
# detects the activated venv via ``VIRTUAL_ENV`` so the venv layout
# downstream jobs rely on is preserved.
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true' && runner.os != 'Windows'
shell: bash
@@ -34,8 +46,8 @@ runs:
python -m venv venv
source venv/bin/activate
python --version
pip install -r requirements.txt -r requirements_test.txt
pip install -e .
uv pip install -r requirements.txt -r requirements_test.txt
uv pip install -e .
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true' && runner.os == 'Windows'
shell: bash
@@ -43,5 +55,5 @@ runs:
python -m venv venv
source ./venv/Scripts/activate
python --version
pip install -r requirements.txt -r requirements_test.txt
pip install -e .
uv pip install -r requirements.txt -r requirements_test.txt
uv pip install -e .

View File

@@ -1 +1 @@
../.ai/instructions.md
../AGENTS.md

View File

@@ -5,6 +5,7 @@ updates:
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
ignore:
# Hypotehsis is only used for testing and is updated quite often
- dependency-name: hypothesis

View File

@@ -35,6 +35,9 @@ module.exports = {
],
DOCS_PR_PATTERNS: [
/https:\/\/github\.com\/esphome\/esphome\.io\/pull\/\d+/,
/esphome\/esphome\.io#\d+/,
// Keep matching the old esphome-docs name during the transition period
/https:\/\/github\.com\/esphome\/esphome-docs\/pull\/\d+/,
/esphome\/esphome-docs#\d+/
]

View File

@@ -1,4 +1,3 @@
const fs = require('fs');
const { DOCS_PR_PATTERNS } = require('./constants');
const {
COMPONENT_REGEX,
@@ -9,6 +8,31 @@ const {
} = require('../detect-tags');
const { loadCodeowners, getEffectiveOwners } = require('../codeowners');
// Top-level `CONFIG_SCHEMA = ...` (assignment) or `CONFIG_SCHEMA: ConfigType = ...` (annotation).
// Ruff/Black enforce exactly one space around `=` and no space before `:`,
// so we can match strictly: `CONFIG_SCHEMA ` or `CONFIG_SCHEMA:`.
const CONFIG_SCHEMA_REGEX = /^CONFIG_SCHEMA[ :]/m;
// Fetch a file's contents from the PR head SHA via the GitHub API.
// The auto-label workflow runs on `pull_request_target`, which checks out the
// base branch — files added by the PR don't exist in the workspace, so we have
// to fetch them from the head SHA. Returns null if the file can't be fetched.
async function fetchPrFileContent(github, context, path) {
try {
const { owner, repo } = context.repo;
const { data } = await github.rest.repos.getContent({
owner,
repo,
path,
ref: context.payload.pull_request.head.sha,
});
return Buffer.from(data.content, 'base64').toString('utf8');
} catch (error) {
console.log(`Failed to fetch ${path} from PR head:`, error.message);
return null;
}
}
// Strategy: Merge branch detection
async function detectMergeBranch(context) {
const labels = new Set();
@@ -45,52 +69,72 @@ async function detectComponentPlatforms(changedFiles, apiData) {
}
// Strategy: New component detection
async function detectNewComponents(prFiles) {
async function detectNewComponents(github, context, prFiles) {
const labels = new Set();
let hasYamlLoadable = false;
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
for (const file of addedFiles) {
const componentMatch = file.match(/^esphome\/components\/([^\/]+)\/__init__\.py$/);
if (componentMatch) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('IS_TARGET_PLATFORM = True')) {
labels.add('new-target-platform');
}
} catch (error) {
console.log(`Failed to read content of ${file}:`, error.message);
}
labels.add('new-component');
if (!componentMatch) continue;
labels.add('new-component');
const content = await fetchPrFileContent(github, context, file);
if (content === null) {
// Safe default: assume YAML-loadable so needs-docs behaviour is unchanged on fetch failure
hasYamlLoadable = true;
continue;
}
if (content.includes('IS_TARGET_PLATFORM = True')) {
labels.add('new-target-platform');
}
if (CONFIG_SCHEMA_REGEX.test(content)) {
hasYamlLoadable = true;
}
}
return labels;
return { labels, hasYamlLoadable };
}
// Strategy: New platform detection
async function detectNewPlatforms(prFiles, apiData) {
async function detectNewPlatforms(github, context, prFiles, apiData) {
const labels = new Set();
let hasYamlLoadable = false;
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
for (const file of addedFiles) {
const platformFileMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/);
if (platformFileMatch) {
const [, component, platform] = platformFileMatch;
if (apiData.platformComponents.includes(platform)) {
labels.add('new-platform');
}
}
const platformPathPatterns = [
/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/,
/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/,
];
const platformDirMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/);
if (platformDirMatch) {
const [, component, platform] = platformDirMatch;
if (apiData.platformComponents.includes(platform)) {
labels.add('new-platform');
const removedFiles = new Set(prFiles.filter(file => file.status === 'removed').map(file => file.filename));
for (const file of addedFiles) {
for (const re of platformPathPatterns) {
const match = file.match(re);
if (!match) continue;
const platform = match[2];
if (!apiData.platformComponents.includes(platform)) break;
// Skip if this is a restructure between flat and subdirectory forms (either direction):
// <component>/<platform>.py <-> <component>/<platform>/__init__.py
const flatEquivalent = `esphome/components/${match[1]}/${platform}.py`;
const subdirEquivalent = `esphome/components/${match[1]}/${platform}/__init__.py`;
if (removedFiles.has(flatEquivalent) || removedFiles.has(subdirEquivalent)) break;
labels.add('new-platform');
const content = await fetchPrFileContent(github, context, file);
if (content === null) {
// Safe default: assume YAML-loadable so needs-docs behaviour is unchanged on fetch failure
hasYamlLoadable = true;
} else if (CONFIG_SCHEMA_REGEX.test(content)) {
hasYamlLoadable = true;
}
break;
}
}
return labels;
return { labels, hasYamlLoadable };
}
// Strategy: Core files detection
@@ -300,7 +344,7 @@ function detectMaintainerAccess(context) {
}
// Strategy: Requirements detection
async function detectRequirements(allLabels, prFiles, context) {
async function detectRequirements(allLabels, prFiles, context, hasYamlLoadable) {
const labels = new Set();
// Check for missing tests
@@ -308,8 +352,15 @@ async function detectRequirements(allLabels, prFiles, context) {
labels.add('needs-tests');
}
// Check for missing docs
if (allLabels.has('new-component') || allLabels.has('new-platform') || allLabels.has('new-feature')) {
// Check for missing docs.
// `new-feature` (PR-body checkbox) always counts. `new-component` / `new-platform`
// only count when at least one newly added file defines a top-level CONFIG_SCHEMA,
// i.e. the new component/platform is actually loadable from YAML.
const docsEligible =
allLabels.has('new-feature') ||
((allLabels.has('new-component') || allLabels.has('new-platform')) && hasYamlLoadable);
if (docsEligible) {
const prBody = context.payload.pull_request.body || '';
const hasDocsLink = DOCS_PR_PATTERNS.some(pattern => pattern.test(prBody));

View File

@@ -106,8 +106,8 @@ module.exports = async ({ github, context }) => {
const [
branchLabels,
componentLabels,
newComponentLabels,
newPlatformLabels,
newComponentResult,
newPlatformResult,
coreLabels,
sizeLabels,
dashboardLabels,
@@ -120,8 +120,8 @@ module.exports = async ({ github, context }) => {
] = await Promise.all([
detectMergeBranch(context),
detectComponentPlatforms(changedFiles, apiData),
detectNewComponents(prFiles),
detectNewPlatforms(prFiles, apiData),
detectNewComponents(github, context, prFiles),
detectNewPlatforms(github, context, prFiles, apiData),
detectCoreChanges(changedFiles),
detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
detectDashboardChanges(changedFiles),
@@ -133,6 +133,13 @@ module.exports = async ({ github, context }) => {
detectMaintainerAccess(context)
]);
// Extract new-component / new-platform results
const newComponentLabels = newComponentResult.labels;
const newPlatformLabels = newPlatformResult.labels;
// Eligible for needs-docs only if any newly added component or platform file
// defines a top-level CONFIG_SCHEMA (i.e. is actually loadable from YAML).
const hasYamlLoadable = newComponentResult.hasYamlLoadable || newPlatformResult.hasYamlLoadable;
// Extract deprecated component info
const deprecatedLabels = deprecatedResult.labels;
const deprecatedInfo = deprecatedResult.deprecatedInfo;
@@ -154,7 +161,7 @@ module.exports = async ({ github, context }) => {
]);
// Detect requirements based on all other labels
const requirementLabels = await detectRequirements(allLabels, prFiles, context);
const requirementLabels = await detectRequirements(allLabels, prFiles, context, hasYamlLoadable);
for (const label of requirementLabels) {
allLabels.add(label);
}

View File

@@ -0,0 +1,7 @@
{
"name": "auto-label-pr",
"private": true,
"scripts": {
"test": "node --test tests/*.test.js"
}
}

View File

@@ -0,0 +1,147 @@
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const { detectNewPlatforms, detectNewComponents } = require('../detectors');
// Minimal GitHub API mock — only repos.getContent is called by detectNewPlatforms/detectNewComponents
// to check for CONFIG_SCHEMA in newly added files.
function makeGithub(content = '') {
return {
rest: {
repos: {
getContent: async () => ({
data: { content: Buffer.from(content).toString('base64') }
})
}
}
};
}
const CONTEXT = {
repo: { owner: 'esphome', repo: 'esphome' },
payload: { pull_request: { head: { sha: 'abc123' }, base: { ref: 'dev' } } }
};
const API_DATA = {
targetPlatforms: ['esp32', 'esp8266', 'rp2040'],
platformComponents: ['cover', 'sensor', 'binary_sensor', 'switch', 'light', 'fan', 'climate', 'valve']
};
const WITH_SCHEMA = 'CONFIG_SCHEMA = cv.Schema({})';
const WITHOUT_SCHEMA = 'CODEOWNERS = ["@esphome/core"]';
// ---------------------------------------------------------------------------
// detectNewPlatforms
// ---------------------------------------------------------------------------
describe('detectNewPlatforms', () => {
describe('restructure detection (no false positives)', () => {
it('flat .py -> subdir __init__.py is not a new platform', async () => {
const prFiles = [
{ filename: 'esphome/components/endstop/cover.py', status: 'removed' },
{ filename: 'esphome/components/endstop/cover/__init__.py', status: 'added' },
];
const result = await detectNewPlatforms(makeGithub(WITH_SCHEMA), CONTEXT, prFiles, API_DATA);
assert.equal(result.labels.size, 0);
assert.equal(result.hasYamlLoadable, false);
});
it('subdir __init__.py -> flat .py is not a new platform', async () => {
const prFiles = [
{ filename: 'esphome/components/endstop/cover/__init__.py', status: 'removed' },
{ filename: 'esphome/components/endstop/cover.py', status: 'added' },
];
const result = await detectNewPlatforms(makeGithub(WITH_SCHEMA), CONTEXT, prFiles, API_DATA);
assert.equal(result.labels.size, 0);
assert.equal(result.hasYamlLoadable, false);
});
});
describe('genuine new platforms', () => {
it('new subdir platform with CONFIG_SCHEMA sets new-platform and hasYamlLoadable', async () => {
const prFiles = [
{ filename: 'esphome/components/my_sensor/cover/__init__.py', status: 'added' },
];
const result = await detectNewPlatforms(makeGithub(WITH_SCHEMA), CONTEXT, prFiles, API_DATA);
assert.ok(result.labels.has('new-platform'));
assert.equal(result.hasYamlLoadable, true);
});
it('new flat platform with CONFIG_SCHEMA sets new-platform and hasYamlLoadable', async () => {
const prFiles = [
{ filename: 'esphome/components/my_sensor/cover.py', status: 'added' },
];
const result = await detectNewPlatforms(makeGithub(WITH_SCHEMA), CONTEXT, prFiles, API_DATA);
assert.ok(result.labels.has('new-platform'));
assert.equal(result.hasYamlLoadable, true);
});
it('new platform without CONFIG_SCHEMA sets new-platform but not hasYamlLoadable', async () => {
const prFiles = [
{ filename: 'esphome/components/my_sensor/cover.py', status: 'added' },
];
const result = await detectNewPlatforms(makeGithub(WITHOUT_SCHEMA), CONTEXT, prFiles, API_DATA);
assert.ok(result.labels.has('new-platform'));
assert.equal(result.hasYamlLoadable, false);
});
it('non-platform file addition produces no labels', async () => {
const prFiles = [
{ filename: 'esphome/components/my_sensor/sensor.py', status: 'added' },
];
// Override platformComponents so 'sensor' is not a recognized platform -> no label expected.
const nonPlatformApiData = { ...API_DATA, platformComponents: ['cover'] };
const result = await detectNewPlatforms(makeGithub(WITH_SCHEMA), CONTEXT, prFiles, nonPlatformApiData);
assert.equal(result.labels.size, 0);
assert.equal(result.hasYamlLoadable, false);
});
});
});
// ---------------------------------------------------------------------------
// detectNewComponents
// ---------------------------------------------------------------------------
describe('detectNewComponents', () => {
it('new top-level __init__.py sets new-component', async () => {
const prFiles = [
{ filename: 'esphome/components/actuator/__init__.py', status: 'added', },
];
const result = await detectNewComponents(makeGithub(WITHOUT_SCHEMA), CONTEXT, prFiles);
assert.ok(result.labels.has('new-component'));
assert.equal(result.hasYamlLoadable, false);
});
it('new top-level __init__.py with CONFIG_SCHEMA sets hasYamlLoadable', async () => {
const prFiles = [
{ filename: 'esphome/components/my_component/__init__.py', status: 'added' },
];
const result = await detectNewComponents(makeGithub(WITH_SCHEMA), CONTEXT, prFiles);
assert.ok(result.labels.has('new-component'));
assert.equal(result.hasYamlLoadable, true);
});
it('new top-level __init__.py with IS_TARGET_PLATFORM sets new-target-platform', async () => {
const prFiles = [
{ filename: 'esphome/components/my_platform/__init__.py', status: 'added' },
];
const result = await detectNewComponents(makeGithub('IS_TARGET_PLATFORM = True'), CONTEXT, prFiles);
assert.ok(result.labels.has('new-component'));
assert.ok(result.labels.has('new-target-platform'));
});
it('modified __init__.py does not set new-component', async () => {
const prFiles = [
{ filename: 'esphome/components/existing/__init__.py', status: 'modified' },
];
const result = await detectNewComponents(makeGithub(WITH_SCHEMA), CONTEXT, prFiles);
assert.equal(result.labels.size, 0);
});
it('nested __init__.py does not set new-component', async () => {
const prFiles = [
{ filename: 'esphome/components/endstop/cover/__init__.py', status: 'added' },
];
const result = await detectNewComponents(makeGithub(WITH_SCHEMA), CONTEXT, prFiles);
assert.equal(result.labels.size, 0);
});
});

View File

@@ -6,9 +6,10 @@ on:
pull_request_target:
types: [labeled, opened, reopened, synchronize, edited]
# All PR/label/review writes are performed with the App token minted below,
# so the workflow's GITHUB_TOKEN only needs read access for checkout.
permissions:
pull-requests: write
contents: read
contents: read # actions/checkout reads the workflow source
env:
SMALL_PR_THRESHOLD: 30
@@ -23,14 +24,18 @@ jobs:
if: github.event.pull_request.state == 'open' && (github.event.action != 'labeled' || github.event.sender.type != 'Bot')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by auto-label-pr/*.js.
permission-contents: read # repos.getContent for CODEOWNERS and file lookups in detectors.js
permission-issues: write # listLabelsOnIssue, addLabels, removeLabel, list/createComment
permission-pull-requests: write # pulls.listFiles, list/create/update/dismissReview
- name: Auto Label PR
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View File

@@ -12,8 +12,8 @@ on:
- ".github/workflows/ci-api-proto.yml"
permissions:
contents: read
pull-requests: write
contents: read # actions/checkout for the PR head
pull-requests: write # pulls.createReview / listReviews / dismissReview when generated proto files are stale
jobs:
check:
@@ -21,11 +21,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
- name: Set up uv
# ``--system`` (below) installs into the setup-python interpreter;
# no venv is created or restored by this workflow.
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Install apt dependencies
run: |
@@ -34,7 +44,7 @@ jobs:
sudo apt install -y protobuf-compiler
protoc --version
- name: Install python dependencies
run: pip install aioesphomeapi -c requirements.txt -r requirements_dev.txt
run: uv pip install --system aioesphomeapi -c requirements.txt -r requirements_dev.txt
- name: Generate files
run: script/api_protobuf/api_protobuf.py
- name: Check for changes

View File

@@ -12,8 +12,8 @@ on:
- ".github/workflows/ci-clang-tidy-hash.yml"
permissions:
contents: read
pull-requests: write
contents: read # actions/checkout for the PR head
pull-requests: write # pulls.createReview / listReviews / dismissReview when the clang-tidy hash is out of date
jobs:
verify-hash:
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0

View File

@@ -22,8 +22,7 @@ on:
- "script/platformio_install_deps.py"
permissions:
contents: read
packages: read
contents: read # actions/checkout only
concurrency:
# yamllint disable-line rule:line-length
@@ -34,6 +33,9 @@ jobs:
check-docker:
name: Build docker containers
runs-on: ${{ matrix.os }}
permissions:
contents: read # actions/checkout to load Dockerfile and build context
packages: write # push branch-tagged images to ghcr.io for local testing
strategy:
fail-fast: false
matrix:
@@ -42,23 +44,94 @@ jobs:
- "ha-addon"
- "docker"
# - "lint"
outputs:
tag: ${{ steps.tag.outputs.tag }}
push: ${{ steps.tag.outputs.push }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Set TAG
- name: Determine tag and whether to push
id: tag
run: |
echo "TAG=check" >> $GITHUB_ENV
# Sanitize the branch name into a valid docker tag: replace invalid
# characters, ensure the first character is valid (tags must start
# with [A-Za-z0-9_]), and cap the length at 128 characters.
branch="${{ github.head_ref || github.ref_name }}"
tag="${branch//[^a-zA-Z0-9_.-]/-}"
case "$tag" in
[a-zA-Z0-9_]*) ;;
*) tag="pr-${tag}" ;;
esac
tag="${tag:0:128}"
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
# Only push branch images for same-repo pull requests. Push events
# only fire for dev/beta/release, whose images are owned by the
# release pipeline -- never overwrite those from here.
if [ "${{ github.event_name }}" = "pull_request" ] \
&& [ "${{ github.repository }}" = "esphome/esphome" ] \
&& [ "${{ github.event.pull_request.head.repo.full_name }}" = "esphome/esphome" ]; then
echo "push=true" >> "$GITHUB_OUTPUT"
else
echo "push=false" >> "$GITHUB_OUTPUT"
fi
- name: Log in to the GitHub container registry
if: steps.tag.outputs.push == 'true'
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run build
run: |
docker/build.py \
--tag "${TAG}" \
--tag "${{ steps.tag.outputs.tag }}" \
--arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
--build-type "${{ matrix.build_type }}" \
build
--registry ghcr \
build ${{ steps.tag.outputs.push == 'true' && '--push --no-cache-to' || '' }}
manifest:
name: Push ${{ matrix.build_type }} manifest to ghcr.io
needs: [check-docker]
if: needs.check-docker.outputs.push == 'true'
runs-on: ubuntu-24.04
permissions:
contents: read # actions/checkout to run docker/build.py
packages: write # buildx imagetools writes the multi-arch tag to ghcr.io
strategy:
fail-fast: false
matrix:
build_type:
- "ha-addon"
- "docker"
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Log in to the GitHub container registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest
run: |
docker/build.py \
--tag "${{ needs.check-docker.outputs.tag }}" \
--build-type "${{ matrix.build_type }}" \
--registry ghcr \
manifest

27
.github/workflows/ci-github-scripts.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: CI - GitHub Scripts
on:
push:
branches: [dev, beta, release]
paths:
- ".github/scripts/**"
- ".github/workflows/ci-github-scripts.yml"
pull_request:
paths:
- ".github/scripts/**"
- ".github/workflows/ci-github-scripts.yml"
permissions:
contents: read
jobs:
test-auto-label-pr:
name: Test auto-label-pr scripts
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Run tests
working-directory: .github/scripts/auto-label-pr
run: npm test

View File

@@ -7,9 +7,9 @@ on:
types: [completed]
permissions:
contents: read
pull-requests: write
actions: read
contents: read # actions/checkout of the base repo at the PR's target branch
pull-requests: write # gh api to look up the PR by head SHA and post/update the memory-impact comment
actions: read # gh run download for the memory-analysis artifacts produced by the CI workflow run
jobs:
memory-impact-comment:
@@ -49,7 +49,7 @@ jobs:
- name: Check out code from base repository
if: steps.pr.outputs.skip != 'true'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Always check out from the base repository (esphome/esphome), never from forks
# Use the PR's target branch to ensure we run trusted code from the main repo

View File

@@ -6,18 +6,10 @@ on:
branches: [dev, beta, release]
pull_request:
paths:
- "**"
- "!.github/workflows/*.yml"
- "!.github/actions/build-image/*"
- ".github/workflows/ci.yml"
- "!.yamllint"
- "!.github/dependabot.yml"
- "!docker/**"
merge_group:
permissions:
contents: read
contents: read # actions/checkout for all jobs; individual jobs add their own scopes when they need to write
env:
DEFAULT_PYTHON: "3.11"
@@ -36,10 +28,10 @@ jobs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Generate cache-key
id: cache-key
run: echo key="${{ hashFiles('requirements.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
run: echo key="${{ hashFiles('requirements.txt', 'requirements_dev.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
@@ -52,14 +44,26 @@ jobs:
path: venv
# yamllint disable-line rule:line-length
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ steps.cache-key.outputs.key }}
- name: Set up uv
# Only needed on cache miss to populate the venv. ``uv pip install``
# detects the activated venv via ``VIRTUAL_ENV`` so downstream jobs
# that ``. venv/bin/activate`` see an identical layout.
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python --version
pip install -r requirements.txt -r requirements_test.txt pre-commit
pip install -e .
uv pip install -r requirements.txt -r requirements_dev.txt -r requirements_test.txt pre-commit
uv pip install -e .
pylint:
name: Check pylint
@@ -70,7 +74,7 @@ jobs:
if: needs.determine-jobs.outputs.python-linters == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -89,9 +93,11 @@ jobs:
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.core-ci == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -107,6 +113,89 @@ jobs:
script/build_language_schema.py --check
script/generate-esp32-boards.py --check
script/generate-rp2040-boards.py --check
script/ci_check_duplicate_test_ids.py
import-time:
name: Check import esphome.__main__ time
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.import-time == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Check import time against budget and write waterfall HAR
run: |
. venv/bin/activate
script/check_import_time.py --check --har importtime.har
- name: Upload waterfall HAR
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: import-time-waterfall
path: importtime.har
if-no-files-found: ignore
retention-days: 14
device-builder:
name: Test downstream esphome/device-builder
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.device-builder == 'true'
steps:
- name: Check out esphome (this PR)
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
path: esphome
- name: Check out esphome/device-builder
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: esphome/device-builder
ref: main
path: device-builder
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Set up uv
# Mirrors the install shape device-builder's own CI uses
# (esphome/device-builder#192): uv replaces pip for the
# install step (order-of-magnitude faster on cold boots,
# with its own wheel cache). actions/setup-python still
# provides the interpreter.
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Install device-builder + esphome from PR
# Install device-builder with its esphome + test extras
# first so its pinned versions of pytest/etc. land, then
# overlay the PR's esphome so the downstream tests run
# against this PR's Python code. ``--system`` installs into
# the runner's Python instead of a venv.
run: |
uv pip install --system -e './device-builder[esphome,test]'
uv pip install --system -e ./esphome
- name: Run device-builder pytest
# ``-n auto`` runs under pytest-xdist (matches device-builder's
# own CI). No ``--cov`` here -- this is purely a downstream
# smoke check against this PR's esphome code. ``tests/e2e/slow``
# is excluded: those are real multi-minute toolchain compiles
# (LibreTiny SDK clone, native ESP-IDF install) that device-builder
# runs in its own dedicated jobs, not this smoke check.
working-directory: device-builder
run: pytest -q -n auto --maxfail=5 --durations=30 --no-cov --ignore=tests/benchmarks --ignore=tests/e2e/slow
pytest:
name: Run pytest
@@ -132,9 +221,11 @@ jobs:
runs-on: ${{ matrix.os }}
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.core-ci == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
id: restore-python
uses: ./.github/actions/restore-python
@@ -147,14 +238,14 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
. ./venv/Scripts/activate.ps1
pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/
pytest -vv --cov-report=xml --tb=native --durations=30 -n auto tests --ignore=tests/integration/
- name: Run pytest
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest'
run: |
. venv/bin/activate
pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/
pytest -vv --cov-report=xml --tb=native --durations=30 -n auto tests --ignore=tests/integration/
- name: Upload coverage to Codecov
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: Save Python virtual environment cache
@@ -170,12 +261,17 @@ jobs:
needs:
- common
outputs:
core-ci: ${{ steps.determine.outputs.core-ci }}
integration-tests: ${{ steps.determine.outputs.integration-tests }}
integration-tests-run-all: ${{ steps.determine.outputs.integration-tests-run-all }}
integration-test-files: ${{ steps.determine.outputs.integration-test-files }}
integration-test-buckets: ${{ steps.determine.outputs.integration-test-buckets }}
clang-tidy: ${{ steps.determine.outputs.clang-tidy }}
clang-tidy-mode: ${{ steps.determine.outputs.clang-tidy-mode }}
clang-tidy-full-scan: ${{ steps.determine.outputs.clang-tidy-full-scan }}
python-linters: ${{ steps.determine.outputs.python-linters }}
import-time: ${{ steps.determine.outputs.import-time }}
device-builder: ${{ steps.determine.outputs.device-builder }}
native-idf: ${{ steps.determine.outputs.native-idf }}
native-idf-components: ${{ steps.determine.outputs.native-idf-components }}
changed-components: ${{ steps.determine.outputs.changed-components }}
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
directly-changed-components-with-tests: ${{ steps.determine.outputs.directly-changed-components-with-tests }}
@@ -185,10 +281,11 @@ jobs:
cpp-unit-tests-run-all: ${{ steps.determine.outputs.cpp-unit-tests-run-all }}
cpp-unit-tests-components: ${{ steps.determine.outputs.cpp-unit-tests-components }}
component-test-batches: ${{ steps.determine.outputs.component-test-batches }}
validate-only-components: ${{ steps.determine.outputs.validate-only-components }}
benchmarks: ${{ steps.determine.outputs.benchmarks }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Fetch enough history to find the merge base
fetch-depth: 2
@@ -208,17 +305,27 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
. venv/bin/activate
output=$(python script/determine-jobs.py)
EXTRA_ARGS=""
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'ci-run-all') }}" == "true" ]]; then
EXTRA_ARGS="--force-all"
echo "::notice::ci-run-all label detected -- forcing every CI job to run"
fi
output=$(python script/determine-jobs.py $EXTRA_ARGS)
echo "Test determination output:"
echo "$output" | jq
# Extract individual fields
echo "core-ci=$(echo "$output" | jq -r '.core_ci')" >> $GITHUB_OUTPUT
echo "integration-tests=$(echo "$output" | jq -r '.integration_tests')" >> $GITHUB_OUTPUT
echo "integration-tests-run-all=$(echo "$output" | jq -r '.integration_tests_run_all')" >> $GITHUB_OUTPUT
echo "integration-test-files=$(echo "$output" | jq -c '.integration_test_files')" >> $GITHUB_OUTPUT
echo "integration-test-buckets=$(echo "$output" | jq -c '.integration_test_buckets')" >> $GITHUB_OUTPUT
echo "clang-tidy=$(echo "$output" | jq -r '.clang_tidy')" >> $GITHUB_OUTPUT
echo "clang-tidy-mode=$(echo "$output" | jq -r '.clang_tidy_mode')" >> $GITHUB_OUTPUT
echo "clang-tidy-full-scan=$(echo "$output" | jq -r '.clang_tidy_full_scan')" >> $GITHUB_OUTPUT
echo "python-linters=$(echo "$output" | jq -r '.python_linters')" >> $GITHUB_OUTPUT
echo "import-time=$(echo "$output" | jq -r '.import_time')" >> $GITHUB_OUTPUT
echo "device-builder=$(echo "$output" | jq -r '.device_builder')" >> $GITHUB_OUTPUT
echo "native-idf=$(echo "$output" | jq -r '.native_idf')" >> $GITHUB_OUTPUT
echo "native-idf-components=$(echo "$output" | jq -r '.native_idf_components')" >> $GITHUB_OUTPUT
echo "changed-components=$(echo "$output" | jq -c '.changed_components')" >> $GITHUB_OUTPUT
echo "changed-components-with-tests=$(echo "$output" | jq -c '.changed_components_with_tests')" >> $GITHUB_OUTPUT
echo "directly-changed-components-with-tests=$(echo "$output" | jq -c '.directly_changed_components_with_tests')" >> $GITHUB_OUTPUT
@@ -228,6 +335,7 @@ jobs:
echo "cpp-unit-tests-run-all=$(echo "$output" | jq -r '.cpp_unit_tests_run_all')" >> $GITHUB_OUTPUT
echo "cpp-unit-tests-components=$(echo "$output" | jq -c '.cpp_unit_tests_components')" >> $GITHUB_OUTPUT
echo "component-test-batches=$(echo "$output" | jq -c '.component_test_batches')" >> $GITHUB_OUTPUT
echo "validate-only-components=$(echo "$output" | jq -c '.validate_only_components')" >> $GITHUB_OUTPUT
echo "benchmarks=$(echo "$output" | jq -r '.benchmarks')" >> $GITHUB_OUTPUT
- name: Save components graph cache
if: github.ref == 'refs/heads/dev'
@@ -237,15 +345,19 @@ jobs:
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
integration-tests:
name: Run integration tests
name: Run integration tests (${{ matrix.bucket.name }})
runs-on: ubuntu-latest
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.integration-tests == 'true'
strategy:
fail-fast: false
matrix:
bucket: ${{ fromJson(needs.determine-jobs.outputs.integration-test-buckets) }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python 3.13
id: python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
@@ -257,31 +369,36 @@ jobs:
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
- name: Set up uv
# Only needed on cache miss to populate the venv.
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python --version
pip install -r requirements.txt -r requirements_test.txt
pip install -e .
uv pip install -r requirements.txt -r requirements_test.txt
uv pip install -e .
- name: Register matcher
run: echo "::add-matcher::.github/workflows/matchers/pytest.json"
- name: Run integration tests
env:
INTEGRATION_TEST_FILES: ${{ needs.determine-jobs.outputs.integration-test-files }}
INTEGRATION_TESTS_RUN_ALL: ${{ needs.determine-jobs.outputs.integration-tests-run-all }}
# JSON array of test paths; parsed into a bash array below to avoid
# shell word-splitting / glob hazards.
BUCKET_TESTS: ${{ toJson(matrix.bucket.tests) }}
run: |
. venv/bin/activate
if [[ "$INTEGRATION_TESTS_RUN_ALL" == "true" ]]; then
echo "Running all integration tests"
pytest -vv --no-cov --tb=native -n auto tests/integration/
else
# Parse JSON array into bash array to avoid shell expansion issues
mapfile -t test_files < <(echo "$INTEGRATION_TEST_FILES" | jq -r '.[]')
echo "Running ${#test_files[@]} specific integration tests"
pytest -vv --no-cov --tb=native -n auto "${test_files[@]}"
fi
mapfile -t test_files < <(echo "$BUCKET_TESTS" | jq -r '.[]')
echo "Bucket ${{ matrix.bucket.name }}: running ${#test_files[@]} integration tests"
pytest -vv --no-cov --tb=native --durations=30 -n auto "${test_files[@]}"
cpp-unit-tests:
name: Run C++ unit tests
@@ -292,7 +409,7 @@ jobs:
if: github.event_name == 'pull_request' && (needs.determine-jobs.outputs.cpp-unit-tests-run-all == 'true' || needs.determine-jobs.outputs.cpp-unit-tests-components != '[]')
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
@@ -321,7 +438,7 @@ jobs:
(github.event_name == 'pull_request' && needs.determine-jobs.outputs.benchmarks == 'true')
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
@@ -339,9 +456,12 @@ jobs:
echo "binary=$BINARY" >> $GITHUB_OUTPUT
- name: Run CodSpeed benchmarks
uses: CodSpeedHQ/action@658a901452bb54c799643e060733b7afe9121b8d # v4.14.0
uses: CodSpeedHQ/action@9d332c4d90b43981c3e55ae8e38e68709996240f # v4.17.0
with:
run: ${{ steps.build.outputs.binary }}
run: |
. venv/bin/activate
${{ steps.build.outputs.binary }}
pytest tests/benchmarks/python/ --codspeed --no-cov
mode: simulation
clang-tidy-single:
@@ -353,6 +473,8 @@ jobs:
if: needs.determine-jobs.outputs.clang-tidy == 'true'
env:
GH_TOKEN: ${{ github.token }}
# esp32-arduino-tidy installs ESP-IDF natively; share the native IDF cache.
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
strategy:
fail-fast: false
max-parallel: 2
@@ -363,9 +485,9 @@ jobs:
options: --environment esp8266-arduino-tidy --grep USE_ESP8266
pio_cache_key: tidyesp8266
- id: clang-tidy
name: Run script/clang-tidy for ESP32 IDF
options: --environment esp32-idf-tidy --grep USE_ESP_IDF
pio_cache_key: tidyesp32-idf
name: Run script/clang-tidy for ESP32 Arduino
options: --environment esp32-arduino-tidy --grep USE_ARDUINO
cache_idf: true
- id: clang-tidy
name: Run script/clang-tidy for ZEPHYR
options: --environment nrf52-tidy --grep USE_ZEPHYR --grep USE_NRF52
@@ -374,7 +496,7 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -386,36 +508,42 @@ jobs:
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
if: github.ref == 'refs/heads/dev' && matrix.pio_cache_key
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
if: github.ref != 'refs/heads/dev' && matrix.pio_cache_key
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
- name: Cache ESP-IDF install
# Shared with the IDF tidy + native-IDF build jobs (same install).
if: matrix.cache_idf
uses: ./.github/actions/cache-esp-idf
with:
framework: arduino
- name: Register problem matchers
run: |
echo "::add-matcher::.github/workflows/matchers/gcc.json"
echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
- name: Run 'pio run --list-targets -e esp32-idf-tidy'
if: matrix.name == 'Run script/clang-tidy for ESP32 IDF'
run: |
. venv/bin/activate
mkdir -p .temp
pio run --list-targets -e esp32-idf-tidy
- name: Check if full clang-tidy scan needed
id: check_full_scan
run: |
. venv/bin/activate
if python script/clang_tidy_hash.py --check; then
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
# OR the ci-run-all label forced --force-all. Independent of the
# hash check, both must produce a full scan in the job itself.
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
elif python script/clang_tidy_hash.py --check; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=hash_changed" >> $GITHUB_OUTPUT
else
@@ -427,7 +555,7 @@ jobs:
run: |
. venv/bin/activate
if [ "${{ steps.check_full_scan.outputs.full_scan }}" = "true" ]; then
echo "Running FULL clang-tidy scan (hash changed)"
echo "Running FULL clang-tidy scan (reason: ${{ steps.check_full_scan.outputs.reason }})"
script/clang-tidy --all-headers --fix ${{ matrix.options }} ${{ matrix.ignore_errors && '|| true' || '' }}
else
echo "Running clang-tidy on changed files only"
@@ -443,7 +571,7 @@ jobs:
if: always()
clang-tidy-nosplit:
name: Run script/clang-tidy for ESP32 Arduino
name: Run script/clang-tidy for ESP32 IDF
runs-on: ubuntu-24.04
needs:
- common
@@ -451,9 +579,11 @@ jobs:
if: needs.determine-jobs.outputs.clang-tidy-mode == 'nosplit'
env:
GH_TOKEN: ${{ github.token }}
# esp32-idf-tidy installs ESP-IDF natively; share the native IDF cache.
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -464,19 +594,9 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache ESP-IDF install
# Shared with the Arduino tidy + native-IDF build jobs (same install).
uses: ./.github/actions/cache-esp-idf
- name: Register problem matchers
run: |
@@ -487,7 +607,13 @@ jobs:
id: check_full_scan
run: |
. venv/bin/activate
if python script/clang_tidy_hash.py --check; then
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
# OR the ci-run-all label forced --force-all. Independent of the
# hash check, both must produce a full scan in the job itself.
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
elif python script/clang_tidy_hash.py --check; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=hash_changed" >> $GITHUB_OUTPUT
else
@@ -499,11 +625,11 @@ jobs:
run: |
. venv/bin/activate
if [ "${{ steps.check_full_scan.outputs.full_scan }}" = "true" ]; then
echo "Running FULL clang-tidy scan (hash changed)"
script/clang-tidy --all-headers --fix --environment esp32-arduino-tidy
echo "Running FULL clang-tidy scan (reason: ${{ steps.check_full_scan.outputs.reason }})"
script/clang-tidy --all-headers --fix --environment esp32-idf-tidy
else
echo "Running clang-tidy on changed files only"
script/clang-tidy --all-headers --fix --changed --environment esp32-arduino-tidy
script/clang-tidy --all-headers --fix --changed --environment esp32-idf-tidy
fi
env:
# Also cache libdeps, store them in a ~/.platformio subfolder
@@ -522,27 +648,26 @@ jobs:
if: needs.determine-jobs.outputs.clang-tidy-mode == 'split'
env:
GH_TOKEN: ${{ github.token }}
# esp32-idf-tidy installs ESP-IDF natively; share the native IDF cache.
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
strategy:
fail-fast: false
max-parallel: 2
max-parallel: 3
matrix:
include:
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 1/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 1
name: Run script/clang-tidy for ESP32 IDF 1/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 1
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 2/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 2
name: Run script/clang-tidy for ESP32 IDF 2/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 2
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 3/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 3
- id: clang-tidy
name: Run script/clang-tidy for ESP32 Arduino 4/4
options: --environment esp32-arduino-tidy --split-num 4 --split-at 4
name: Run script/clang-tidy for ESP32 IDF 3/3
options: --environment esp32-idf-tidy --split-num 3 --split-at 3
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -553,19 +678,9 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache ESP-IDF install
# Shared with the Arduino tidy + native-IDF build jobs (same install).
uses: ./.github/actions/cache-esp-idf
- name: Register problem matchers
run: |
@@ -576,7 +691,13 @@ jobs:
id: check_full_scan
run: |
. venv/bin/activate
if python script/clang_tidy_hash.py --check; then
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
# OR the ci-run-all label forced --force-all. Independent of the
# hash check, both must produce a full scan in the job itself.
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
elif python script/clang_tidy_hash.py --check; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=hash_changed" >> $GITHUB_OUTPUT
else
@@ -588,7 +709,7 @@ jobs:
run: |
. venv/bin/activate
if [ "${{ steps.check_full_scan.outputs.full_scan }}" = "true" ]; then
echo "Running FULL clang-tidy scan (hash changed)"
echo "Running FULL clang-tidy scan (reason: ${{ steps.check_full_scan.outputs.reason }})"
script/clang-tidy --all-headers --fix ${{ matrix.options }}
else
echo "Running clang-tidy on changed files only"
@@ -602,6 +723,93 @@ jobs:
run: script/ci-suggest-changes
if: always()
clang-tidy-esp32-variants:
name: ${{ matrix.name }}
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.clang-tidy == 'true'
env:
GH_TOKEN: ${{ github.token }}
# The variant tidy envs install ESP-IDF natively; share the native IDF cache.
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
strategy:
fail-fast: false
max-parallel: 3
matrix:
include:
- id: clang-tidy
name: Run script/clang-tidy for ESP32 S3
options: --environment esp32s3-idf-tidy --grep USE_ESP32_VARIANT_ESP32S3
- id: clang-tidy
name: Run script/clang-tidy for ESP32 P4
# P4 has no native Wi-Fi/BLE; those run over the hosted co-processor,
# so their code paths differ -- lint them under the P4 build too.
# yamllint disable-line rule:line-length
options: --environment esp32p4-idf-tidy --grep USE_ESP32_VARIANT_ESP32P4 --grep USE_ESP32_HOSTED --grep USE_WIFI --grep USE_BLE
- id: clang-tidy
name: Run script/clang-tidy for ESP32 C6
# yamllint disable-line rule:line-length
options: --environment esp32c6-idf-tidy --grep USE_ESP32_VARIANT_ESP32C6 --grep USE_OPENTHREAD --grep USE_ZIGBEE
steps:
- name: Check out code from GitHub
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache ESP-IDF install
# Shared with the IDF/Arduino clang-tidy jobs + native-IDF build (same install).
uses: ./.github/actions/cache-esp-idf
- name: Register problem matchers
run: |
echo "::add-matcher::.github/workflows/matchers/gcc.json"
echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
- name: Check if full clang-tidy scan needed
id: check_full_scan
run: |
. venv/bin/activate
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
# OR the ci-run-all label forced --force-all. Independent of the
# hash check, both must produce a full scan in the job itself.
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
elif python script/clang_tidy_hash.py --check; then
echo "full_scan=true" >> $GITHUB_OUTPUT
echo "reason=hash_changed" >> $GITHUB_OUTPUT
else
echo "full_scan=false" >> $GITHUB_OUTPUT
echo "reason=normal" >> $GITHUB_OUTPUT
fi
- name: Run clang-tidy
# Limited variant scan: only the files carrying that variant's code paths
# (no --all-headers; the comprehensive esp32-idf pass covers the shared tree).
run: |
. venv/bin/activate
if [ "${{ steps.check_full_scan.outputs.full_scan }}" = "true" ]; then
echo "Running FULL clang-tidy scan (reason: ${{ steps.check_full_scan.outputs.reason }})"
script/clang-tidy --fix ${{ matrix.options }}
else
echo "Running clang-tidy on changed files only"
script/clang-tidy --fix --changed ${{ matrix.options }}
fi
- name: Suggested changes
run: script/ci-suggest-changes
if: always()
test-build-components-split:
name: Test components batch (${{ matrix.components }})
runs-on: ubuntu-24.04
@@ -630,7 +838,7 @@ jobs:
version: 1.0
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -687,7 +895,7 @@ jobs:
fi
echo ""
# Show disk space before validation (after bind mounts setup)
# Show disk space before validation
echo "Disk space before config validation:"
df -h
echo ""
@@ -699,23 +907,141 @@ jobs:
echo "Config validation passed! Starting compilation..."
echo ""
# Compute the compile-stage component list. Components whose only
# changes are validate.*.yaml files are config-only -- their source
# and test fixtures didn't move, so rebuilding firmware adds no
# signal. Subtract them from this batch before invoking compile.
validate_only_json='${{ needs.determine-jobs.outputs.validate-only-components }}'
if [ -z "$validate_only_json" ]; then
validate_only_json='[]'
fi
if ! validate_only_csv=$(echo "$validate_only_json" | jq -r 'join(",")'); then
echo "::error::Failed to render validate-only-components as CSV from: $validate_only_json"
exit 1
fi
if [ -z "$validate_only_csv" ]; then
compile_csv="$components_csv"
else
components_sorted=$(echo "$components_csv" | tr ',' '\n' | sort -u)
validate_sorted=$(echo "$validate_only_csv" | tr ',' '\n' | sort -u)
if ! diff_out=$(comm -23 <(echo "$components_sorted") <(echo "$validate_sorted")); then
echo "::error::Failed to compute compile component subset."
exit 1
fi
compile_csv=$(echo "$diff_out" | paste -sd ',' -)
skipped=$(comm -12 <(echo "$components_sorted") <(echo "$validate_sorted") | paste -sd ',' -)
if [ -n "$skipped" ]; then
echo "Validate-only components in this batch (skipping compile): $skipped"
fi
fi
# Show disk space before compilation
echo "Disk space before compilation:"
df -h
echo ""
# Run compilation with grouping and isolation
python3 script/test_build_components.py -e compile -c "$components_csv" -f --isolate "$directly_changed_csv"
if [ -n "$compile_csv" ]; then
# Run compilation with grouping and isolation
python3 script/test_build_components.py -e compile -c "$compile_csv" -f --isolate "$directly_changed_csv"
else
echo "All components in this batch are validate-only -- skipping compile stage."
fi
test-native-idf:
name: Test components with native ESP-IDF
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: github.event_name == 'pull_request' && needs.determine-jobs.outputs.native-idf == 'true'
env:
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
# Comma-joined subset of the native-IDF representative component list,
# computed by script/determine-jobs.py (native_idf_components_to_test).
# Single source of truth -- the full list lives in
# script/determine-jobs.py::NATIVE_IDF_TEST_COMPONENTS.
TEST_COMPONENTS: ${{ needs.determine-jobs.outputs.native-idf-components }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Prepare build storage on /mnt
# Bind-mount the larger /mnt disk over the IDF install + build dirs BEFORE
# restoring the cache, so the ~4.5GB restore lands on the roomier volume
# instead of being shadowed by a mount set up later in the run step.
run: |
root_avail=$(df -k / | awk 'NR==2 {print $4}')
mnt_avail=$(df -k /mnt 2>/dev/null | awk 'NR==2 {print $4}')
echo "Available space: / has ${root_avail}KB, /mnt has ${mnt_avail}KB"
if [ -n "$mnt_avail" ] && [ "$mnt_avail" -gt "$root_avail" ]; then
echo "Using /mnt for build files (more space available)"
sudo mkdir -p /mnt/esphome-idf
sudo chown $USER:$USER /mnt/esphome-idf
mkdir -p ~/.esphome-idf
sudo mount --bind /mnt/esphome-idf ~/.esphome-idf
sudo mkdir -p /mnt/test_build_components_build
sudo chown $USER:$USER /mnt/test_build_components_build
mkdir -p tests/test_build_components/build
sudo mount --bind /mnt/test_build_components_build tests/test_build_components/build
else
echo "Using / for build files (more space available than /mnt or /mnt unavailable)"
fi
- name: Cache ESP-IDF install
# Shared with the IDF/Arduino clang-tidy jobs (same install); restores
# into the /mnt bind-mount prepared above when present.
uses: ./.github/actions/cache-esp-idf
- name: Run native ESP-IDF compile test
run: |
. venv/bin/activate
echo "Testing components: $TEST_COMPONENTS"
echo ""
# Show disk space before validation
echo "Disk space before config validation:"
df -h
echo ""
# Run config validation (auto-grouped by test_build_components.py)
python3 script/test_build_components.py -e config -t esp32-idf -c "$TEST_COMPONENTS" -f --toolchain esp-idf
echo ""
echo "Config validation passed! Starting compilation..."
echo ""
# Show disk space before compilation
echo "Disk space before compilation:"
df -h
echo ""
# Run compilation (auto-grouped by test_build_components.py)
python3 script/test_build_components.py -e compile -t esp32-idf -c "$TEST_COMPONENTS" -f --toolchain esp-idf
- name: Save ESPHome cache
if: github.ref == 'refs/heads/dev'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.esphome-idf
key: ${{ runner.os }}-esphome-${{ needs.common.outputs.cache-key }}
pre-commit-ci-lite:
name: pre-commit.ci lite
runs-on: ubuntu-latest
needs:
- common
if: github.event_name == 'pull_request' && !startsWith(github.base_ref, 'beta') && !startsWith(github.base_ref, 'release')
- determine-jobs
if: github.event_name == 'pull_request' && !startsWith(github.base_ref, 'beta') && !startsWith(github.base_ref, 'release') && needs.determine-jobs.outputs.core-ci == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -741,7 +1067,7 @@ jobs:
skip: ${{ steps.check-script.outputs.skip || steps.check-tests.outputs.skip }}
steps:
- name: Check out target branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.base_ref }}
@@ -923,7 +1249,7 @@ jobs:
flash_usage: ${{ steps.extract.outputs.flash_usage }}
steps:
- name: Check out PR branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -986,13 +1312,13 @@ jobs:
- memory-impact-pr-branch
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true' && needs.memory-impact-target-branch.outputs.skip != 'true'
permissions:
contents: read
pull-requests: write
contents: read # actions/checkout to load the comment-posting script
pull-requests: write # ci_memory_impact_comment.py posts/updates the memory-impact comment on the PR
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -1035,8 +1361,11 @@ jobs:
- clang-tidy-single
- clang-tidy-nosplit
- clang-tidy-split
- clang-tidy-esp32-variants
- determine-jobs
- device-builder
- test-build-components-split
- test-native-idf
- pre-commit-ci-lite
- memory-impact-target-branch
- memory-impact-pr-branch

View File

@@ -6,8 +6,8 @@ on:
types: [opened, reopened]
permissions:
pull-requests: write
issues: write
pull-requests: write # pulls.update to close the PR opened from a fork's default branch
issues: write # issues.createComment to explain to the contributor why the PR was closed
jobs:
close:

View File

@@ -15,9 +15,9 @@ on:
- beta
permissions:
issues: write
pull-requests: read
contents: read
issues: write # issues.addLabels / removeLabel to manage the 'code-owner-approved' label on the PR
pull-requests: read # listReviews to determine whether a codeowner has approved
contents: read # actions/checkout to read CODEOWNERS and the shared codeowners.js helper
jobs:
codeowner-approved:
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout base branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.event.pull_request.base.sha }}
sparse-checkout: |

View File

@@ -17,9 +17,10 @@ on:
- release
- beta
# PR/review writes (requestReviewers, issues.createComment) are performed with the App token minted below,
# so the workflow's GITHUB_TOKEN only needs read access for checkout.
permissions:
pull-requests: write
contents: read
contents: read # actions/checkout to read CODEOWNERS and the shared codeowners.js helper
jobs:
request-codeowner-reviews:
@@ -28,13 +29,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout base branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.event.pull_request.base.sha }}
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by the github-script step below.
permission-pull-requests: write # pulls.listFiles, pulls.get, pulls.listReviews, pulls.requestReviewers
permission-issues: write # issues.listComments and issues.createComment (PR comments use the issues API)
- name: Request reviews from component codeowners
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const { loadCodeowners, getEffectiveOwners } = require('./.github/scripts/codeowners.js');

View File

@@ -16,6 +16,9 @@ on:
schedule:
- cron: "30 18 * * 4"
# Deny by default; the analyze job opts in to exactly what it needs.
permissions: {}
jobs:
analyze:
name: Analyze (${{ matrix.language }})
@@ -26,15 +29,10 @@ jobs:
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
security-events: write # upload CodeQL SARIF results to the Code Scanning API
packages: read # fetch internal or private CodeQL query packs
actions: read # required by codeql-action when run from a private repo
contents: read # actions/checkout to scan the repository
strategy:
fail-fast: false
@@ -54,11 +52,11 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@@ -86,6 +84,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
category: "/language:${{matrix.language}}"

View File

@@ -0,0 +1,119 @@
name: Add Dashboard Deprecation Comment
on:
pull_request_target:
types: [opened, synchronize]
# All API calls (pulls.listFiles + issues.{list,create,update}Comment) are performed with
# the App token minted below, so the workflow's GITHUB_TOKEN does not need any scopes.
permissions: {}
jobs:
dashboard-deprecation-comment:
name: Dashboard deprecation comment
runs-on: ubuntu-latest
# Release-bump PRs (bump-X.Y.Z -> beta, beta -> release) inevitably
# roll up everything merged into dev since the last cut, which can
# include dashboard changes that have already been reviewed once.
# The bot's purpose is to warn new contributors before they invest
# time -- that only applies to PRs entering dev.
if: github.event.pull_request.base.ref == 'dev'
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# pulls.listFiles + issues.{list,create,update}Comment on PRs. For PR resources
# the issues.*Comment APIs require the pull-requests scope, not issues.
permission-pull-requests: write
- name: Add dashboard deprecation comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const commentMarker = "<!-- This comment was generated automatically by the dashboard-deprecation-comment workflow. -->";
const commentBody = `Thanks for opening this PR!
Heads up: the legacy ESPHome dashboard (\`esphome/dashboard/\` and \`tests/dashboard/\`) is **deprecated** and is being replaced by [ESPHome Device Builder](https://github.com/esphome/device-builder). We are not adding new features to the legacy dashboard and it will eventually be removed from this repository.
What this means for your PR:
- **New features / enhancements**: please port the change to [esphome/device-builder](https://github.com/esphome/device-builder) instead. We are unlikely to review or merge new dashboard features here.
- **Bug fixes**: small fixes may still be considered, but please check first whether the same issue exists in Device Builder, where the fix will have a longer life.
- **Security issues**: please do not file a public PR. Report privately via [GitHub security advisories](https://github.com/esphome/esphome/security/advisories/new) so we can coordinate a fix.
We appreciate the contribution and apologize for the friction; flagging this early so your time isn't spent on a change that may not land.
---
(Added by the PR bot)
${commentMarker}`;
async function getDashboardChanges(github, owner, repo, prNumber) {
const changedFiles = await github.paginate(
github.rest.pulls.listFiles,
{
owner: owner,
repo: repo,
pull_number: prNumber,
per_page: 100,
}
);
return changedFiles.filter(file =>
file.filename.startsWith('esphome/dashboard/') ||
file.filename.startsWith('tests/dashboard/')
);
}
async function findBotComment(github, owner, repo, prNumber) {
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: owner,
repo: repo,
issue_number: prNumber,
per_page: 100,
}
);
return comments.find(comment =>
comment.body.includes(commentMarker) && comment.user.type === "Bot"
);
}
const prNumber = context.payload.pull_request.number;
const { owner, repo } = context.repo;
const dashboardChanges = await getDashboardChanges(github, owner, repo, prNumber);
const existingComment = await findBotComment(github, owner, repo, prNumber);
if (dashboardChanges.length === 0) {
// PR doesn't (or no longer) touches the legacy dashboard. If we previously
// commented (e.g. files were removed in a later push), leave the comment in
// place for history rather than thrash on edit/delete.
return;
}
if (existingComment) {
if (existingComment.body === commentBody) {
return;
}
await github.rest.issues.updateComment({
owner: owner,
repo: repo,
comment_id: existingComment.id,
body: commentBody,
});
} else {
await github.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: prNumber,
body: commentBody,
});
}

View File

@@ -4,20 +4,29 @@ on:
pull_request_target:
types: [opened, synchronize]
permissions:
contents: read # Needed to fetch PR details
issues: write # Needed to create and update comments (PR comments are managed via the issues REST API)
pull-requests: write # also needed?
# All API calls (pulls.listFiles + issues.{list,create,update}Comment) are performed with
# the App token minted below, so the workflow's GITHUB_TOKEN does not need any scopes.
permissions: {}
jobs:
external-comment:
name: External component comment
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# pulls.listFiles + issues.{list,create,update}Comment on PRs. For PR resources
# the issues.*Comment APIs require the pull-requests scope, not issues.
permission-pull-requests: write
- name: Add external component comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
github-token: ${{ steps.generate-token.outputs.token }}
script: |
// Generate external component usage instructions
function generateExternalComponentInstructions(prNumber, componentNames, owner, repo) {

View File

@@ -9,8 +9,8 @@ on:
types: [labeled]
permissions:
issues: write
contents: read
issues: write # issues.createComment to mention component codeowners on the newly labelled issue
contents: read # repos.getContent to fetch CODEOWNERS from the default branch
jobs:
notify-codeowners:

View File

@@ -6,6 +6,12 @@ on:
- cron: "30 0 * * *" # Run daily at 00:30 UTC
workflow_dispatch:
# Deny by default; the lock job opts in to exactly what the reusable workflow needs.
permissions: {}
jobs:
lock:
uses: esphome/workflows/.github/workflows/lock.yml@3c4e8446aa1029f1c346a482034b3ee1489077ca # 2026.4.0
permissions:
issues: write # issues.lock on closed issues
pull-requests: write # issues.lock on closed pull requests
uses: esphome/workflows/.github/workflows/lock.yml@025a1e6255610c498ed590403b7e510b69e474df # 2026.4.1

View File

@@ -8,15 +8,15 @@ on:
- beta
permissions:
contents: read
pull-requests: read
contents: read # actions/checkout to load detect-tags.js
pull-requests: read # pulls.listFiles to map changed files to component/core/dashboard/ci tags
jobs:
check:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
@@ -29,10 +29,11 @@ jobs:
} = require('./.github/scripts/detect-tags.js');
const title = context.payload.pull_request.title;
const author = context.payload.pull_request.user.login;
const user = context.payload.pull_request.user;
// Skip bot PRs (e.g. dependabot) - they have their own title format
if (author === 'dependabot[bot]') {
// Skip bot PRs (e.g. dependabot, esphome[bot] device-class sync) -
// they have their own title formats.
if (user.type === 'Bot') {
return;
}
@@ -68,14 +69,15 @@ jobs:
return;
}
// Check for angle brackets not wrapped in backticks.
// Astro docs MDX treats bare < as JSX component opening tags.
// Check for MDX syntax characters not wrapped in backticks.
// Astro docs MDX treats bare `<` as JSX component opening tags and
// bare `{` as JS expressions, so both must be escaped in changelog entries.
const stripped = title.replace(/`[^`]*`/g, '');
if (/[<>]/.test(stripped)) {
if (/[<>{}]/.test(stripped)) {
core.setFailed(
'PR title contains `<` or `>` not wrapped in backticks.\n' +
'Astro docs MDX interprets bare `<` as JSX components.\n' +
'Please wrap angle brackets with backticks, e.g.: [component] Add `<feature>` support'
'PR title contains `<`, `>`, `{`, or `}` not wrapped in backticks.\n' +
'Astro docs MDX interprets bare `<` as JSX components and bare `{` as JS expressions.\n' +
'Please wrap these characters with backticks, e.g.: [component] Add `<feature>` support'
);
return;
}

View File

@@ -9,7 +9,7 @@ on:
- cron: "0 2 * * *"
permissions:
contents: read
contents: read # actions/checkout for all jobs; deploy jobs add their own scopes when they need to write
jobs:
init:
@@ -20,7 +20,7 @@ jobs:
branch_build: ${{ steps.tag.outputs.branch_build }}
deploy_env: ${{ steps.tag.outputs.deploy_env }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Get tag
id: tag
# yamllint disable rule:line-length
@@ -57,10 +57,10 @@ jobs:
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
contents: read # actions/checkout to build the sdist/wheel
id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish)
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
@@ -78,8 +78,8 @@ jobs:
name: Build ESPHome ${{ matrix.platform.arch }}
if: github.repository == 'esphome/esphome'
permissions:
contents: read
packages: write
contents: read # actions/checkout to load Dockerfile and build context
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
runs-on: ${{ matrix.platform.os }}
needs: [init]
strategy:
@@ -92,22 +92,22 @@ jobs:
os: "ubuntu-24.04-arm"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Log in to docker hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -152,8 +152,8 @@ jobs:
- deploy-docker
if: github.repository == 'esphome/esphome'
permissions:
contents: read
packages: write
contents: read # actions/checkout to load Dockerfile and build context
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
strategy:
fail-fast: false
matrix:
@@ -168,7 +168,7 @@ jobs:
- ghcr
- dockerhub
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
@@ -178,17 +178,17 @@ jobs:
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Log in to docker hub
if: matrix.registry == 'dockerhub'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to the GitHub container registry
if: matrix.registry == 'ghcr'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -212,72 +212,6 @@ jobs:
docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \
$(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *)
deploy-ha-addon-repo:
if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
runs-on: ubuntu-latest
needs:
- init
- deploy-manifest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: home-assistant-addon
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
let description = "ESPHome";
if (context.eventName == "release") {
description = ${{ toJSON(github.event.release.body) }};
}
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "home-assistant-addon",
workflow_id: "bump-version.yml",
ref: "main",
inputs: {
version: "${{ needs.init.outputs.tag }}",
content: description
}
})
deploy-esphome-schema:
if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
runs-on: ubuntu-latest
needs: [init]
environment: ${{ needs.init.outputs.deploy_env }}
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: esphome-schema
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "esphome-schema",
workflow_id: "generate-schemas.yml",
ref: "main",
inputs: {
version: "${{ needs.init.outputs.tag }}",
}
})
version-notifier:
if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
runs-on: ubuntu-latest
@@ -287,19 +221,20 @@ jobs:
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: version-notifier
permission-actions: write # actions.createWorkflowDispatch on the target repo (only API call made with this token)
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
github.rest.actions.createWorkflowDispatch({
await github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "version-notifier",
workflow_id: "notify.yml",

View File

@@ -7,8 +7,8 @@ on:
workflow_dispatch:
permissions:
issues: write
pull-requests: write
issues: write # actions/stale labels, comments on, and closes stale issues
pull-requests: write # actions/stale labels, comments on, and closes stale pull requests
concurrency:
group: lock
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Stale
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
with:
debug-only: ${{ github.ref != 'refs/heads/dev' }} # Dry-run when not run on dev branch
remove-stale-when-updated: true

View File

@@ -4,6 +4,9 @@ on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
permissions:
pull-requests: read # issues.listLabelsOnIssue to detect blocking labels (needs-docs, merge-after-release, chained-pr)
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

View File

@@ -6,17 +6,32 @@ on:
schedule:
- cron: "45 6 * * *"
# Repo writes (branch push, PR open) happen via the App token minted below,
# so the workflow's GITHUB_TOKEN does not need any write scopes.
permissions:
contents: read # actions/checkout for this repo and home-assistant/core
jobs:
sync:
name: Sync Device Classes
runs-on: ubuntu-latest
if: github.repository == 'esphome/esphome'
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by peter-evans/create-pull-request.
permission-contents: write # git.createCommit + refs.create/update to push the sync/device-classes branch
permission-pull-requests: write # pulls.create / pulls.update to open or refresh the sync PR
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Checkout Home Assistant
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: home-assistant/core
path: lib/home-assistant
@@ -26,19 +41,56 @@ jobs:
with:
python-version: "3.14"
- name: Set up uv
# An order of magnitude faster than pip on cold boots, with its
# own wheel cache. ``--system`` (below) installs into the
# setup-python interpreter so subsequent ``pre-commit`` /
# ``script/run-in-env.py`` steps find the deps without a
# ``uv run`` prefix.
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
# Pin uv version so the action does not have to fetch the
# manifest from raw.githubusercontent.com on every cache
# miss; that fetch flakes on Windows runners.
version: "0.11.15"
- name: Install Home Assistant
run: |
python -m pip install --upgrade pip
pip install -e lib/home-assistant
pip install -r requirements_test.txt pre-commit
uv pip install --system -e lib/home-assistant
uv pip install --system -r requirements.txt -r requirements_test.txt pre-commit
- name: Sync
run: |
python ./script/sync-device_class.py
- name: Run pre-commit hooks
run: |
python script/run-in-env.py pre-commit run --all-files
- name: Apply pre-commit auto-fixes
# First pass: let formatters (ruff, end-of-file-fixer, etc.) modify
# files. pre-commit exits non-zero whenever a hook touches anything,
# which would otherwise abort the workflow before the auto-fixes
# can flow into the sync PR.
#
# SKIP:
# - no-commit-to-branch is a local guard against committing on
# dev/release/beta; CI runs on dev by definition, and
# peter-evans/create-pull-request creates the branch itself.
# - pylint surfaces import-error / relative-beyond-top-level
# noise here because this workflow installs only a subset of
# the runtime deps (HA + requirements*.txt); main CI already
# gates pylint on real PRs.
env:
SKIP: pylint,no-commit-to-branch
run: python script/run-in-env.py pre-commit run --all-files || true
- name: Verify pre-commit clean
# Second pass: re-run all hooks against the now-fixed tree.
# Auto-fixers exit 0 (nothing to change); any remaining failure
# from a check-only hook (flake8 / yamllint / ci-custom) is a
# real issue and fails the workflow loudly. Same SKIP list as
# above for the same reasons.
env:
SKIP: pylint,no-commit-to-branch
run: python script/run-in-env.py pre-commit run --all-files
- name: Commit changes
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
@@ -50,4 +102,4 @@ jobs:
delete-branch: true
title: "Synchronise Device Classes from Home Assistant"
body-path: .github/PULL_REQUEST_TEMPLATE.md
token: ${{ secrets.DEVICE_CLASS_SYNC_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}

2
.gitignore vendored
View File

@@ -141,10 +141,12 @@ tests/.esphome/
sdkconfig.*
!sdkconfig.defaults
!sdkconfig.defaults.*
.tests/
/components
/managed_components
/dependencies.lock
api-docs/

View File

@@ -11,7 +11,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.12
rev: v0.15.15
hooks:
# Run the linter.
- id: ruff
@@ -55,7 +55,7 @@ repos:
hooks:
- id: pylint
name: pylint
entry: python3 script/run-in-env.py pylint
entry: python script/run-in-env.py pylint
language: system
types: [python]
files: ^esphome/.+\.py$
@@ -63,10 +63,10 @@ repos:
name: Update clang-tidy hash
entry: python script/clang_tidy_hash.py --update-if-changed
language: python
files: ^(\.clang-tidy|platformio\.ini|requirements_dev\.txt)$
files: ^(\.clang-tidy|platformio\.ini|requirements_dev\.txt|sdkconfig\.defaults|esphome/idf_component\.yml)$
pass_filenames: false
additional_dependencies: []
- id: ci-custom
name: ci-custom
entry: python3 script/run-in-env.py script/ci-custom.py
entry: python script/run-in-env.py script/ci-custom.py
language: system

View File

@@ -398,13 +398,23 @@ This document provides essential context for AI models interacting with this pro
│ ├── i2c/ # I2C bus
│ └── spi/ # SPI bus
└── components/[component]/
├── common.yaml # Component-only config (no bus definitions)
├── test.esp32-idf.yaml
├── test.esp8266-ard.yaml
── test.rp2040-ard.yaml
├── 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 using `script/test_build_components`. Use `-c <component>` to test specific components and `-t <target>` for specific platforms.
* **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 things like 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 entirely 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.
* **Test 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/`:
```yaml
# test.esp32-idf.yaml — use packages for buses
@@ -452,7 +462,7 @@ This document provides essential context for AI models interacting with this pro
6. **Pull Request:** Submit a PR against the `dev` branch. The Pull Request title should have a prefix of the component being worked on (e.g., `[display] Fix bug`, `[abc123] Add new component`). Update documentation, examples, and add `CODEOWNERS` entries as needed. Pull requests should always be made using the `.github/PULL_REQUEST_TEMPLATE.md` template - fill out all sections completely without removing any parts of the template.
* **Documentation Contributions:**
* Documentation is hosted in the separate `esphome/esphome-docs` repository.
* Documentation is hosted in the separate `esphome/esphome.io` repository.
* The contribution workflow is the same as for the codebase.
* When editing a component's documentation page, also update the corresponding component index page to ensure both pages remain in sync.
@@ -671,7 +681,7 @@ This document provides essential context for AI models interacting with this pro
- [ ] Explored non-breaking alternatives
- [ ] Added deprecation warnings if possible (use `ESPDEPRECATED` macro for C++)
- [ ] Documented migration path in PR description with before/after examples
- [ ] Updated all internal usage and esphome-docs
- [ ] Updated all internal usage and esphome.io
- [ ] Tested backward compatibility during deprecation period
* **Deprecation Pattern (C++):**

View File

@@ -1 +1 @@
.ai/instructions.md
AGENTS.md

View File

@@ -19,7 +19,6 @@ esphome/components/ac_dimmer/* @glmnet
esphome/components/adc/* @esphome/core
esphome/components/adc128s102/* @DeerMaximum
esphome/components/addressable_light/* @justfalter
esphome/components/ade7880/* @kpfleming
esphome/components/ade7953/* @angelnu
esphome/components/ade7953_base/* @angelnu
esphome/components/ade7953_i2c/* @angelnu
@@ -28,7 +27,7 @@ esphome/components/ads1118/* @solomondg1
esphome/components/ags10/* @mak-42
esphome/components/aic3204/* @kbx81
esphome/components/airthings_ble/* @jeromelaban
esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau
esphome/components/airthings_wave_base/* @jeromelaban @ncareau
esphome/components/airthings_wave_mini/* @ncareau
esphome/components/airthings_wave_plus/* @jeromelaban @precurse
esphome/components/alarm_control_panel/* @grahambrown11 @hwstar
@@ -84,6 +83,7 @@ esphome/components/bme680_bsec/* @trvrnrth
esphome/components/bme68x_bsec2/* @kbx81 @neffs
esphome/components/bme68x_bsec2_i2c/* @kbx81 @neffs
esphome/components/bmi160/* @flaviut
esphome/components/bmi270/* @clydebarrow
esphome/components/bmp280_base/* @ademuri
esphome/components/bmp280_i2c/* @ademuri
esphome/components/bmp280_spi/* @ademuri
@@ -139,7 +139,7 @@ esphome/components/dfplayer/* @glmnet
esphome/components/dfrobot_sen0395/* @niklasweber
esphome/components/dht/* @OttoWinter
esphome/components/display_menu_base/* @numo68
esphome/components/dlms_meter/* @SimonFischer04
esphome/components/dlms_meter/* @latonita @PolarGoose @SimonFischer04 @Tomer27cz
esphome/components/dps310/* @kbx81
esphome/components/ds1307/* @badbadc0ffee
esphome/components/ds2484/* @mrk-its
@@ -291,6 +291,7 @@ esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/logger/select/* @clydebarrow
esphome/components/lps22/* @nagisa
esphome/components/lsm6ds/* @clydebarrow
esphome/components/ltr390/* @latonita @sjtrny
esphome/components/ltr501/* @latonita
esphome/components/ltr_als_ps/* @latonita
@@ -347,9 +348,11 @@ esphome/components/modbus_controller/select/* @martgras @stegm
esphome/components/modbus_controller/sensor/* @martgras
esphome/components/modbus_controller/switch/* @martgras
esphome/components/modbus_controller/text_sensor/* @martgras
esphome/components/modbus_server/* @exciton
esphome/components/mopeka_ble/* @Fabian-Schmidt @spbrogan
esphome/components/mopeka_pro_check/* @spbrogan
esphome/components/mopeka_std_check/* @Fabian-Schmidt
esphome/components/motion/* @esphome/core
esphome/components/mpl3115a2/* @kbickar
esphome/components/mpu6886/* @fabaff
esphome/components/ms8607/* @e28eta
@@ -378,6 +381,7 @@ esphome/components/pca6416a/* @Mat931
esphome/components/pca9554/* @bdraco @clydebarrow @hwstar
esphome/components/pcf85063/* @brogon
esphome/components/pcf8563/* @KoenBreeman
esphome/components/pcm5122/* @remcom
esphome/components/pi4ioe5v6408/* @jesserockz
esphome/components/pid/* @OttoWinter
esphome/components/pipsolar/* @andreashergert1984
@@ -415,6 +419,8 @@ esphome/components/resampler/speaker/* @kahrendt
esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz
esphome/components/rgbct/* @jesserockz
esphome/components/ring_buffer/* @kahrendt
esphome/components/router/speaker/* @kahrendt
esphome/components/rp2040/* @jesserockz
esphome/components/rp2040_ble/* @bdraco
esphome/components/rp2040_pio_led_strip/* @Papa-DMan
@@ -592,6 +598,7 @@ esphome/components/wk2212_spi/* @DrCoolZic
esphome/components/wl_134/* @hobbypunk90
esphome/components/wts01/* @alepee
esphome/components/x9c/* @EtienneMD
esphome/components/xdb401/* @RT530
esphome/components/xgzp68xx/* @gcormier
esphome/components/xiaomi_hhccjcy10/* @fariouche
esphome/components/xiaomi_lywsd02mmc/* @juanluss31

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2026.5.0-dev
PROJECT_NUMBER = 2026.6.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -1 +1 @@
.ai/instructions.md
AGENTS.md

18
codecov.yml Normal file
View File

@@ -0,0 +1,18 @@
coverage:
status:
patch:
default:
target: 100%
threshold: 0%
project:
default:
informational: true
ignore:
- "esphome/components/**/*"
- "esphome/analyze_memory/**/*"
- "tests/integration/**/*"
comment:
layout: "reach, diff, flags, files"
require_changes: true

View File

@@ -1,10 +1,9 @@
ARG BUILD_VERSION=dev
ARG BUILD_OS=alpine
ARG BUILD_BASE_VERSION=2025.04.0
ARG BUILD_BASE_VERSION=2026.06.0
ARG BUILD_TYPE=docker
FROM ghcr.io/esphome/docker-base:${BUILD_OS}-${BUILD_BASE_VERSION} AS base-source-docker
FROM ghcr.io/esphome/docker-base:${BUILD_OS}-ha-addon-${BUILD_BASE_VERSION} AS base-source-ha-addon
FROM ghcr.io/esphome/docker-base:debian-${BUILD_BASE_VERSION} AS base-source-docker
FROM ghcr.io/esphome/docker-base:debian-ha-addon-${BUILD_BASE_VERSION} AS base-source-ha-addon
ARG BUILD_TYPE
FROM base-source-${BUILD_TYPE} AS base
@@ -13,14 +12,14 @@ RUN git config --system --add safe.directory "*" \
&& git config --system advice.detachedHead false
# Install build tools for Python packages that require compilation
# (e.g., ruamel.yaml.clibz used by ESP-IDF's idf-component-manager)
RUN if command -v apk > /dev/null; then \
apk add --no-cache build-base; \
else \
apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*; \
fi
# (e.g., ruamel.yaml.clib used by ESP-IDF's idf-component-manager).
# Also install libusb-1.0 at runtime so the ESP-IDF tools installer can
# validate openocd-esp32 (it dynamically links libusb-1.0.so.0); without
# it idf_tools.py rejects the openocd install with exit 127 and aborts
# the whole framework setup.
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential libusb-1.0-0 \
&& rm -rf /var/lib/apt/lists/*
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
@@ -32,6 +31,9 @@ RUN \
uv pip install --no-cache-dir \
-r /requirements.txt
# Install the ESPHome Device Builder dashboard.
RUN uv pip install --no-cache-dir esphome-device-builder==1.0.12
RUN \
platformio settings set enable_telemetry No \
&& platformio settings set check_platformio_interval 1000000 \

View File

@@ -20,6 +20,10 @@ TYPE_HA_ADDON = "ha-addon"
TYPE_LINT = "lint"
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
REGISTRY_GHCR = "ghcr"
REGISTRY_DOCKERHUB = "dockerhub"
REGISTRIES = [REGISTRY_GHCR, REGISTRY_DOCKERHUB]
parser = argparse.ArgumentParser()
parser.add_argument(
@@ -34,6 +38,12 @@ parser.add_argument(
parser.add_argument(
"--build-type", choices=TYPES, required=True, help="The type of build to run"
)
parser.add_argument(
"--registry",
choices=REGISTRIES,
action="append",
help="Restrict to specific registries (default: all). May be passed multiple times.",
)
parser.add_argument(
"--dry-run", action="store_true", help="Don't run any commands, just print them"
)
@@ -45,6 +55,11 @@ build_parser.add_argument("--push", help="Also push the images", action="store_t
build_parser.add_argument(
"--load", help="Load the docker image locally", action="store_true"
)
build_parser.add_argument(
"--no-cache-to",
help="Don't write the build cache (avoids polluting the shared cache)",
action="store_true",
)
manifest_parser = subparsers.add_parser(
"manifest", help="Create a manifest from already pushed images"
)
@@ -95,11 +110,14 @@ def main():
print("Command failed")
sys.exit(1)
registries = args.registry or REGISTRIES
# detect channel from tag
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
major_minor_version = None
if match is None:
channel = CHANNEL_DEV
# Custom tag (e.g. a branch name) -- push only the tag itself
channel = None
elif match.group(2) is None:
major_minor_version = match.group(1)
channel = CHANNEL_RELEASE
@@ -128,11 +146,18 @@ def main():
CHANNEL_DEV: "cache-dev",
CHANNEL_BETA: "cache-beta",
CHANNEL_RELEASE: "cache-latest",
}[channel]
cache_img = f"ghcr.io/{params.build_to}:{cache_tag}"
}.get(channel, "cache-dev")
# Cache images live alongside the pushed images; prefer GHCR when it is
# one of the selected registries, otherwise fall back to Docker Hub so a
# registry-restricted build doesn't need GHCR auth.
cache_prefix = "ghcr.io/" if REGISTRY_GHCR in registries else ""
cache_img = f"{cache_prefix}{params.build_to}:{cache_tag}"
imgs = [f"{params.build_to}:{tag}" for tag in tags_to_push]
imgs += [f"ghcr.io/{params.build_to}:{tag}" for tag in tags_to_push]
imgs = []
if REGISTRY_DOCKERHUB in registries:
imgs += [f"{params.build_to}:{tag}" for tag in tags_to_push]
if REGISTRY_GHCR in registries:
imgs += [f"ghcr.io/{params.build_to}:{tag}" for tag in tags_to_push]
# 3. build
cmd = [
@@ -155,7 +180,9 @@ def main():
for img in imgs:
cmd += ["--tag", img]
if args.push:
cmd += ["--push", "--cache-to", f"type=registry,ref={cache_img},mode=max"]
cmd += ["--push"]
if not args.no_cache_to:
cmd += ["--cache-to", f"type=registry,ref={cache_img},mode=max"]
if args.load:
cmd += ["--load"]
@@ -163,20 +190,22 @@ def main():
elif args.command == "manifest":
manifest = DockerParams.for_type_arch(args.build_type, ARCH_AMD64).manifest_to
targets = [f"{manifest}:{tag}" for tag in tags_to_push]
targets += [f"ghcr.io/{manifest}:{tag}" for tag in tags_to_push]
# 1. Create manifests
targets = []
if REGISTRY_DOCKERHUB in registries:
targets += [f"{manifest}:{tag}" for tag in tags_to_push]
if REGISTRY_GHCR in registries:
targets += [f"ghcr.io/{manifest}:{tag}" for tag in tags_to_push]
# Use buildx imagetools (not `docker manifest`) so the per-arch sources,
# which buildx pushes as single-platform manifest lists, are combined
# and pushed correctly in one step.
for target in targets:
cmd = ["docker", "manifest", "create", target]
cmd = ["docker", "buildx", "imagetools", "create", "--tag", target]
for arch in ARCHS:
src = f"{DockerParams.for_type_arch(args.build_type, arch).build_to}:{args.tag}"
if target.startswith("ghcr.io"):
src = f"ghcr.io/{src}"
cmd.append(src)
run_command(*cmd)
# 2. Push manifests
for target in targets:
run_command("docker", "manifest", "push", target)
if __name__ == "__main__":

View File

@@ -27,4 +27,12 @@ if [[ -d /build ]]; then
export ESPHOME_BUILD_PATH=/build
fi
# The default CMD is "dashboard /config". Route the dashboard to the new
# Device Builder, but pass every other subcommand (compile, run, config,
# logs, ...) straight through to the esphome CLI so direct CLI use keeps working.
if [[ "$1" == "dashboard" ]]; then
shift
exec esphome-device-builder "$@"
fi
exec esphome "$@"

View File

@@ -1,96 +0,0 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@@ -1,16 +0,0 @@
proxy_http_version 1.1;
proxy_ignore_client_abort off;
proxy_read_timeout 86400s;
proxy_redirect off;
proxy_send_timeout 86400s;
proxy_max_temp_file_size 0;
proxy_set_header Accept-Encoding "";
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization "";

View File

@@ -1,8 +0,0 @@
root /dev/null;
server_name $hostname;
client_max_body_size 512m;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;

View File

@@ -1,8 +0,0 @@
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;

View File

@@ -1,3 +0,0 @@
upstream esphome {
server unix:/var/run/esphome.sock;
}

View File

@@ -1,30 +0,0 @@
daemon off;
user root;
pid /var/run/nginx.pid;
worker_processes 1;
error_log /proc/1/fd/1 error;
events {
worker_connections 1024;
}
http {
include /etc/nginx/includes/mime.types;
access_log off;
default_type application/octet-stream;
gzip on;
keepalive_timeout 65;
sendfile on;
server_tokens off;
tcp_nodelay on;
tcp_nopush on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/includes/upstream.conf;
include /etc/nginx/servers/*.conf;
}

View File

@@ -1 +0,0 @@
Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)

View File

@@ -1,28 +0,0 @@
server {
{{ if not .ssl }}
listen 6052 default_server;
{{ else }}
listen 6052 default_server ssl http2;
{{ end }}
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
{{ if .ssl }}
include /etc/nginx/includes/ssl_params.conf;
ssl_certificate /ssl/{{ .certfile }};
ssl_certificate_key /ssl/{{ .keyfile }};
# Redirect http requests to https on the same port.
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
error_page 497 https://$http_host$request_uri;
{{ end }}
# Clear Home Assistant Ingress header
proxy_set_header X-HA-Ingress "";
location / {
proxy_pass http://esphome;
}
}

View File

@@ -1,18 +0,0 @@
server {
listen 127.0.0.1:{{ .port }} default_server;
listen {{ .interface }}:{{ .port }} default_server;
include /etc/nginx/includes/server_params.conf;
include /etc/nginx/includes/proxy_params.conf;
# Set Home Assistant Ingress header
proxy_set_header X-HA-Ingress "YES";
location / {
allow 172.30.32.2;
allow 127.0.0.1;
deny all;
proxy_pass http://esphome;
}
}

View File

@@ -16,7 +16,7 @@ fi
port=$(bashio::addon.ingress_port)
# Wait for NGINX to become available
# Wait for the ESPHome Device Builder to become available
bashio::net.wait_for "${port}" "127.0.0.1" 300
config=$(\

View File

@@ -2,7 +2,7 @@
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Community Add-on: ESPHome
# Take down the S6 supervision tree when ESPHome dashboard fails
# Take down the S6 supervision tree when ESPHome Device Builder fails
# ==============================================================================
declare exit_code
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
@@ -10,7 +10,7 @@ readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
bashio::log.info \
"Service ESPHome dashboard exited with code ${exit_code_service}" \
"Service ESPHome Device Builder exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then

View File

@@ -2,7 +2,7 @@
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the ESPHome dashboard
# Runs the ESPHome Device Builder
# ==============================================================================
readonly pio_cache_base=/data/cache/platformio
@@ -49,5 +49,21 @@ if bashio::fs.directory_exists '/config/esphome/.esphome'; then
rm -rf /config/esphome/.esphome
fi
bashio::log.info "Starting ESPHome dashboard..."
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
# Only signal device-builder to expose the public LAN port when the operator
# mapped port 6052, matching the legacy dashboard where nginx listened on the
# fixed port 6052 only when it was configured. We use the mapping purely as a
# presence check and don't forward the published value; device-builder binds
# its default port 6052 (the fixed container port, as the legacy
# "listen 6052" did). --ha-addon-allow-public is inert on its own: the no-auth
# gate is the DISABLE_HA_AUTHENTICATION env var set above, so both opt-ins are
# required to bind 6052 unauthenticated; either alone stays ingress-only.
set --
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
set -- --ha-addon-allow-public
fi
bashio::log.info "Starting ESPHome Device Builder..."
exec esphome-device-builder /config/esphome \
--ha-addon \
--ingress-port "$(bashio::addon.ingress_port)" \
"$@"

View File

@@ -1,27 +0,0 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Configures NGINX for use with ESPHome
# ==============================================================================
mkdir -p /var/log/nginx
# Generate Ingress configuration
bashio::var.json \
interface "$(bashio::addon.ip_address)" \
port "^$(bashio::addon.ingress_port)" \
| tempio \
-template /etc/nginx/templates/ingress.gtpl \
-out /etc/nginx/servers/ingress.conf
# Generate direct access configuration, if enabled.
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
bashio::config.require.ssl
bashio::var.json \
certfile "$(bashio::config 'certfile')" \
keyfile "$(bashio::config 'keyfile')" \
ssl "^$(bashio::config 'ssl')" \
| tempio \
-template /etc/nginx/templates/direct.gtpl \
-out /etc/nginx/servers/direct.conf
fi

View File

@@ -1 +0,0 @@
/etc/s6-overlay/s6-rc.d/init-nginx/run

View File

@@ -1,25 +0,0 @@
#!/command/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when NGINX fails
# ==============================================================================
declare exit_code
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
bashio::log.info \
"Service NGINX exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt
fi

View File

@@ -1,15 +0,0 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the NGINX proxy
# ==============================================================================
bashio::log.info "Waiting for ESPHome dashboard to come up..."
while [[ ! -S /var/run/esphome.sock ]]; do
sleep 0.5
done
bashio::log.info "Starting NGINX..."
exec nginx

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ from .helpers import (
from .toolchain import find_tool, resolve_tool_path, run_tool
if TYPE_CHECKING:
from esphome.platformio_api import IDEData
from esphome.platformio.toolchain import IDEData
_LOGGER = logging.getLogger(__name__)
@@ -793,8 +793,11 @@ class MemoryAnalyzer:
"""Scan ESPHome source object files to map extern "C" symbols to components.
When no linker map file is available, this uses ``nm`` to scan ``.o`` files
under ``src/esphome/`` and build a symbol-to-component mapping. This catches
``extern "C"`` functions and other symbols that lack C++ namespace prefixes.
under ``src/`` (including ``src/main.cpp.o`` and everything beneath
``src/esphome/``) and build a symbol-to-component mapping. This catches
``extern "C"`` functions, the ESPHome-generated ``setup()``/``loop()``
entry points in ``main.cpp``, and other symbols that lack C++ namespace
prefixes.
Skips scanning if ``_source_symbol_map`` was already populated by
``_parse_map_file()``.
@@ -806,12 +809,12 @@ class MemoryAnalyzer:
if obj_dir is None:
return
# Find ESPHome source object files
esphome_src_dir = obj_dir / "src" / "esphome"
if not esphome_src_dir.is_dir():
# Scan all ESPHome-owned source object files: src/main.cpp.o and src/esphome/...
src_dir = obj_dir / "src"
if not src_dir.is_dir():
return
obj_files = sorted(esphome_src_dir.rglob("*.o"))
obj_files = sorted(src_dir.rglob("*.o"))
if not obj_files:
return
@@ -1064,6 +1067,10 @@ class MemoryAnalyzer:
if component_name in self.external_components:
return f"{_COMPONENT_PREFIX_EXTERNAL}{component_name}"
# ESPHome-generated entry point: src/main.cpp.o (contains setup()/loop())
if len(parts) >= 2 and parts[-2:] == ("src", "main.cpp.o"):
return _COMPONENT_CORE
# ESPHome core: src/esphome/core/... or src/esphome/...
if "core" in parts and "esphome" in parts:
return _COMPONENT_CORE

View File

@@ -6,6 +6,7 @@ from collections import defaultdict
from collections.abc import Callable
import heapq
from operator import itemgetter
from pathlib import Path
import sys
from typing import TYPE_CHECKING
@@ -509,7 +510,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
lines.append(
f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):"
)
for i, (symbol, demangled, size) in enumerate(large_core_symbols):
for i, (_symbol, demangled, size) in enumerate(large_core_symbols):
# Core symbols only track (symbol, demangled, size) without section info,
# so we don't show section labels here
lines.append(
@@ -601,7 +602,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
lines.append(
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B & storage ({len(large_symbols)} symbols):"
)
for i, (symbol, demangled, size, section) in enumerate(large_symbols):
for i, (_symbol, demangled, size, section) in enumerate(large_symbols):
lines.append(
f"{i + 1}. {self._format_symbol_with_section(demangled, size, section)}"
)
@@ -640,7 +641,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
lines.append(
f" Symbols > {self.RAM_SYMBOL_SIZE_THRESHOLD} B ({len(large_ram_syms)}):"
)
for symbol, demangled, size, section in large_ram_syms[:10]:
for _symbol, demangled, size, section in large_ram_syms[:10]:
# Format section label consistently by stripping leading dot
section_label = section.lstrip(".") if section else ""
display_name = _format_pstorage_name(demangled)
@@ -699,7 +700,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
content = "\n".join(lines)
if output_file:
with open(output_file, "w", encoding="utf-8") as f:
with Path(output_file).open("w", encoding="utf-8") as f:
f.write(content)
else:
print(content)
@@ -737,9 +738,8 @@ def main():
# Load build directory
import json
from pathlib import Path
from esphome.platformio_api import IDEData
from esphome.platformio.toolchain import IDEData
build_path = Path(build_dir)
@@ -785,7 +785,7 @@ def main():
if not idedata_path.exists():
continue
try:
with open(idedata_path, encoding="utf-8") as f:
with idedata_path.open(encoding="utf-8") as f:
raw_data = json.load(f)
idedata = IDEData(raw_data)
print(f"Loaded idedata from: {idedata_path}", file=sys.stderr)

View File

@@ -154,7 +154,7 @@ def batch_demangle(
failed_count = 0
for original, stripped, prefix, demangled in zip(
symbols, symbols_stripped, symbols_prefixes, demangled_lines
symbols, symbols_stripped, symbols_prefixes, demangled_lines, strict=True
):
# Add back any prefix that was removed
demangled = _restore_symbol_prefix(prefix, stripped, demangled)

View File

@@ -3,7 +3,6 @@
from __future__ import annotations
import logging
import os
from pathlib import Path
import subprocess
from typing import TYPE_CHECKING
@@ -37,7 +36,7 @@ def _find_in_platformio_packages(tool_name: str) -> str | None:
Full path to the tool or None if not found
"""
# Get PlatformIO packages directory
platformio_home = Path(os.path.expanduser("~/.platformio/packages"))
platformio_home = Path("~/.platformio/packages").expanduser()
if not platformio_home.exists():
return None

View File

@@ -45,7 +45,7 @@ class AsyncThreadRunner(threading.Thread, Generic[_T]):
async def _runner(self) -> None:
try:
self.result = await self._coro_factory()
except Exception as exc: # pylint: disable=broad-except
except Exception as exc: # noqa: BLE001 # pylint: disable=broad-except
# Capture all exceptions so ``event`` is always set — otherwise a
# crash would hang the waiter forever.
self.exception = exc

View File

@@ -127,7 +127,7 @@ def validate_potentially_or_condition(value):
return validate_condition(value)
DelayAction = cg.esphome_ns.class_("DelayAction", Action, cg.Component)
DelayAction = cg.esphome_ns.class_("DelayAction", Action)
LambdaAction = cg.esphome_ns.class_("LambdaAction", Action)
StatelessLambdaAction = cg.esphome_ns.class_("StatelessLambdaAction", Action)
IfAction = cg.esphome_ns.class_("IfAction", Action)
@@ -396,7 +396,6 @@ async def delay_action_to_code(
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_component(var, {})
template_ = await cg.templatable(config, args, cg.uint32)
cg.add(var.set_delay(template_))
return var
@@ -597,7 +596,7 @@ async def component_resume_action_to_code(
comp = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, comp)
if CONF_UPDATE_INTERVAL in config:
template_ = await cg.templatable(config[CONF_UPDATE_INTERVAL], args, int)
template_ = await cg.templatable(config[CONF_UPDATE_INTERVAL], args, cg.uint32)
cg.add(var.set_update_interval(template_))
return var

View File

@@ -3,23 +3,38 @@
import json
from pathlib import Path
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32 import get_esp32_variant, idf_version
import esphome.config_validation as cv
from esphome.core import CORE
from esphome.helpers import mkdir_p, write_file_if_changed
# Replaces the IDF default C++ standard (-std=gnu++2b appended to
# CXX_COMPILE_OPTIONS by project.cmake's __build_init) with the one set via
# cg.set_cpp_standard(). Emitted between include(project.cmake) and project(),
# i.e. after IDF appends its default and before the options are consumed, and
# applies project-wide like PlatformIO build_unflags.
CPP_STANDARD_TEMPLATE = """\
idf_build_get_property(esphome_cxx_compile_options CXX_COMPILE_OPTIONS)
list(FILTER esphome_cxx_compile_options EXCLUDE REGEX "^-std=")
list(APPEND esphome_cxx_compile_options "-std={standard}")
idf_build_set_property(CXX_COMPILE_OPTIONS "${{esphome_cxx_compile_options}}")"""
def get_available_components() -> list[str] | None:
"""Get list of available ESP-IDF components from project_description.json.
"""Get list of built-in ESP-IDF components from project_description.json.
Returns only internal ESP-IDF components, excluding external/managed
components (from idf_component.yml).
Excludes ``src``, IDF-managed components (``managed_components/``), and
converted PIO libs (``pio_components/``). Returns ``None`` if the build
dir or ``project_description.json`` isn't ready yet.
"""
if CORE.build_path is None:
return None
project_desc = Path(CORE.build_path) / "build" / "project_description.json"
if not project_desc.exists():
return None
try:
with open(project_desc, encoding="utf-8") as f:
with project_desc.open(encoding="utf-8") as f:
data = json.load(f)
component_info = data.get("build_component_info", {})
@@ -30,9 +45,9 @@ def get_available_components() -> list[str] | None:
if name == "src":
continue
# Exclude managed/external components
# Exclude IDF-managed and converted-PIO components (external).
comp_dir = info.get("dir", "")
if "managed_components" in comp_dir:
if "managed_components" in comp_dir or "pio_components" in comp_dir:
continue
result.append(name)
@@ -47,72 +62,161 @@ def has_discovered_components() -> bool:
return get_available_components() is not None
def get_project_cmakelists() -> str:
"""Generate the top-level CMakeLists.txt for ESP-IDF project."""
def get_project_cmakelists(minimal: bool = False) -> str:
"""Generate the top-level CMakeLists.txt for ESP-IDF project.
When ``minimal`` is true, omit ``ESPHOME_PROJECT_BUILTIN_COMPONENTS``
since ``project_description.json`` may be stale on the first write.
"""
# Get IDF target from ESP32 variant (e.g., ESP32S3 -> esp32s3)
variant = get_esp32_variant()
idf_target = variant.lower().replace("-", "")
# Extract compile definitions from build flags (-DXXX -> XXX)
compile_defs = [flag for flag in CORE.build_flags if flag.startswith("-D")]
# esp_idf_size 2.x (bundled with IDF >=6.0) made NG the default and
# removed the --ng flag; on 1.x (IDF 5.5) --ng is required to get
# --format=raw because the legacy mode doesn't support it.
size_ng_flag = "--ng" if idf_version() < cv.Version(6, 0, 0) else ""
# Project-wide compile options: -D defines and -W warning flags (skip
# -Wl, linker flags — those go on the src component via
# target_link_options below). Emitted via idf_build_set_property so the
# flags propagate to every IDF component (including managed ones like
# esphome__micro-mp3) rather than just src/. Required so suppressions
# like ``-Wno-error=maybe-uninitialized`` actually silence warnings in
# third-party components we don't author.
project_compile_opts = [
flag
for flag in sorted(CORE.build_flags)
if flag.startswith("-D")
or (flag.startswith("-W") and not flag.startswith("-Wl,"))
]
extra_compile_options = "\n".join(
f'idf_build_set_property(COMPILE_OPTIONS "{compile_def}" APPEND)'
for compile_def in compile_defs
f'idf_build_set_property(COMPILE_OPTIONS "{flag}" APPEND)'
for flag in project_compile_opts
)
cpp_standard_options = (
CPP_STANDARD_TEMPLATE.format(standard=CORE.cpp_standard)
if CORE.cpp_standard
else ""
)
# Per-project list exposed as a CMake variable so converted PIO libs
# can reference ${ESPHOME_PROJECT_MANAGED_COMPONENTS} without baking
# project-specific names into their cached CMakeLists.
#
# Emit via idf_build_set_property (not plain set()) so the value is
# serialised into build_properties.temp.cmake and visible to IDF's
# early requirements-expansion pass (component_get_requirements.cmake
# runs as a separate CMake script invocation that doesn't load the
# project's top-level CMakeLists; without this, ${ESPHOME_PROJECT_
# MANAGED_COMPONENTS} in a converted-lib REQUIRES expands to empty).
from esphome.components.esp32 import get_managed_component_require_names
managed_components_property = "\n".join(
f"idf_build_set_property(ESPHOME_PROJECT_MANAGED_COMPONENTS {name} APPEND)"
for name in get_managed_component_require_names()
)
# Built-in IDF components exposed via our own property (not IDF's
# __COMPONENT_REQUIRES_COMMON, which would append them to every
# component's REQUIRES including real IDF components). Referenced by
# src/CMakeLists and by each converted PIO lib's CMakeLists. Skipped
# on minimal writes because project_description.json may be stale.
builtin_components_property = (
""
if minimal
else "\n".join(
f"idf_build_set_property(ESPHOME_PROJECT_BUILTIN_COMPONENTS {name} APPEND)"
for name in sorted(get_available_components() or [])
)
)
return f"""\
# Auto-generated by ESPHome
cmake_minimum_required(VERSION 3.16)
# On Windows, Ninja can fail with:
# "CreateProcess: The parameter is incorrect (is the command line too long?)"
# when compiler/linker command lines exceed the OS length limit.
#
# The following settings force CMake/Ninja to use *response files* (@file.rsp)
# to pass long lists of includes, objects, and other arguments indirectly,
# avoiding command-line length limits and fixing the build failure.
#
# This is especially useful for large ESP-IDF / ESPHome projects with many
# source files or include directories.
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)
set(IDF_TARGET {idf_target})
set(EXTRA_COMPONENT_DIRS ${{CMAKE_SOURCE_DIR}}/src)
include($ENV{{IDF_PATH}}/tools/cmake/project.cmake)
{cpp_standard_options}
{extra_compile_options}
{managed_components_property}
{builtin_components_property}
project({CORE.name})
# Emit raw JSON size data for ESPHome to read post-build.
add_custom_command(
TARGET ${{CMAKE_PROJECT_NAME}}.elf POST_BUILD
COMMAND ${{PYTHON}} -m esp_idf_size {size_ng_flag} --format=raw
-o ${{CMAKE_BINARY_DIR}}/esp_idf_size.json
${{CMAKE_PROJECT_NAME}}.map
WORKING_DIRECTORY ${{CMAKE_BINARY_DIR}}
VERBATIM
)
"""
def get_component_cmakelists(minimal: bool = False) -> str:
"""Generate the main component CMakeLists.txt."""
idf_requires = [] if minimal else (get_available_components() or [])
requires_str = " ".join(idf_requires)
def get_component_cmakelists() -> str:
"""Generate the main component CMakeLists.txt.
# Extract compile options (-W flags, excluding linker flags)
compile_opts = [
flag
for flag in CORE.build_flags
if flag.startswith("-W") and not flag.startswith("-Wl,")
]
compile_opts_str = "\n ".join(sorted(compile_opts)) if compile_opts else ""
# Extract linker options (-Wl, flags)
REQUIRES pulls in the discovered built-in IDF components via the
project-level variables set in the top-level CMakeLists.
"""
# Extract linker options (-Wl, flags). Compile flags (-D, -W) are
# emitted project-wide via idf_build_set_property in
# get_project_cmakelists so they reach every component, not just src/.
link_opts = [flag for flag in CORE.build_flags if flag.startswith("-Wl,")]
link_opts_str = "\n ".join(sorted(link_opts)) if link_opts else ""
return f"""\
# Auto-generated by ESPHome
file(GLOB_RECURSE app_sources
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.c"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.c"
)
# CONFIGURE_DEPENDS asks CMake to re-check the glob each build so test
# runs that reuse the build dir don't compile stale source paths. It's
# invalid in script mode (cmake -P), which is how IDF's
# component_get_requirements.cmake includes us, so skip it there.
if(CMAKE_SCRIPT_MODE_FILE)
file(GLOB_RECURSE app_sources
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.c"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.c"
)
else()
file(GLOB_RECURSE app_sources CONFIGURE_DEPENDS
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/*.c"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.cpp"
"${{CMAKE_CURRENT_SOURCE_DIR}}/esphome/*.c"
)
endif()
idf_component_register(
SRCS ${{app_sources}}
INCLUDE_DIRS "." "esphome"
REQUIRES {requires_str}
)
# Apply C++ standard
target_compile_features(${{COMPONENT_LIB}} PUBLIC cxx_std_20)
# ESPHome compile options
target_compile_options(${{COMPONENT_LIB}} PUBLIC
{compile_opts_str}
REQUIRES ${{ESPHOME_PROJECT_BUILTIN_COMPONENTS}}
)
# ESPHome linker options
@@ -130,11 +234,11 @@ def write_project(minimal: bool = False) -> None:
# Write top-level CMakeLists.txt
write_file_if_changed(
CORE.relative_build_path("CMakeLists.txt"),
get_project_cmakelists(),
get_project_cmakelists(minimal=minimal),
)
# Write component CMakeLists.txt in src/
write_file_if_changed(
CORE.relative_src_path("CMakeLists.txt"),
get_component_cmakelists(minimal=minimal),
get_component_cmakelists(),
)

View File

@@ -1,7 +1,7 @@
from esphome.const import __version__
from esphome.core import CORE
from esphome.helpers import mkdir_p, read_file, write_file_if_changed
from esphome.writer import find_begin_end, update_storage_json
from esphome.writer import find_begin_end
INI_AUTO_GENERATE_BEGIN = "; ========== AUTO GENERATED CODE BEGIN ==========="
INI_AUTO_GENERATE_END = "; =========== AUTO GENERATED CODE END ============"
@@ -33,12 +33,27 @@ def format_ini(data: dict[str, str | list[str]]) -> str:
return content
# All -std= variants a platform/framework may set by default, in both the GNU
# and strict dialects; unflagged so the cg.set_cpp_standard() value is the
# only standard left in the build.
CPP_STD_VARIANTS = [
f"{prefix}{year}"
for year in ("11", "14", "17", "20", "23", "26", "2a", "2b", "2c")
for prefix in ("gnu++", "c++")
]
def get_ini_content():
CORE.add_platformio_option(
"lib_deps",
[x.as_lib_dep for x in CORE.platformio_libraries.values()]
+ ["${common.lib_deps}"],
)
if CORE.cpp_standard:
for variant in CPP_STD_VARIANTS:
if variant != CORE.cpp_standard:
CORE.add_build_unflag(f"-std={variant}")
CORE.add_build_flag(f"-std={CORE.cpp_standard}")
# Sort to avoid changing build flags order
CORE.add_platformio_option("build_flags", sorted(CORE.build_flags))
@@ -58,7 +73,6 @@ def get_ini_content():
def write_ini(content):
update_storage_json()
path = CORE.relative_build_path("platformio.ini")
if path.is_file():

View File

@@ -98,11 +98,13 @@ _KNOWN_FILE_EXTENSIONS = frozenset(
)
# Matches !secret references in YAML text. This is intentionally a simple
# regex scan rather than a YAML parse — it may match inside comments or
# multi-line strings, which is the conservative direction (include more
# secrets rather than fewer).
_SECRET_RE = re.compile(r"!secret\s+(\S+)")
# Matches !secret references in YAML text. An optional surrounding
# quote pair around the key is allowed and ignored: YAML treats
# ``!secret 'foo'`` and ``!secret foo`` as the same key. This is
# intentionally a simple regex scan rather than a YAML parse — it may
# match inside comments or multi-line strings, which is the conservative
# direction (include more secrets rather than fewer).
_SECRET_RE = re.compile(r"""!secret\s+['"]?([^\s'"]+)""")
def _find_used_secret_keys(yaml_files: list[Path]) -> set[str]:
@@ -258,42 +260,20 @@ class ConfigBundleCreator:
def _discover_yaml_includes(self) -> None:
"""Discover YAML files loaded during config parsing.
Deliberately uses a fresh re-parse and force-loads every deferred
``IncludeFile`` to include *all* potentially-reachable includes,
even branches not selected by the local substitutions. Bundles are
meant to be compiled on another system where command-line
substitution overrides may choose a different branch — e.g.
``!include network/${eth_model}/config.yaml`` must ship every
candidate so the remote build can pick any one.
Entries with unresolved substitution variables in the filename
path are skipped with a warning (they cannot be resolved without
the substitution pass).
Secrets files are tracked separately so we can filter them to
only include the keys this config actually references.
Delegates to :func:`yaml_util.discover_user_yaml_files`, which does a
fresh re-parse and force-loads every deferred ``IncludeFile`` so that
*all* potentially-reachable includes are captured (even branches not
selected by local substitutions). Bundles are meant to be compiled on
another system where command-line substitution overrides may choose a
different branch — e.g. ``!include network/${eth_model}/config.yaml``
must ship every candidate so the remote build can pick any one.
"""
# Must be a fresh parse: IncludeFile.load() caches its result in
# _content, and we discover files by listening for loader calls. On
# an already-parsed tree the cache is populated, .load() returns
# without calling the loader, the listener never fires, and the
# referenced files would be silently dropped from the bundle.
with yaml_util.track_yaml_loads() as loaded_files:
try:
data = yaml_util.load_yaml(self._config_path)
except EsphomeError:
_LOGGER.debug(
"Bundle: re-loading YAML for include discovery failed, "
"proceeding with partial file list"
)
else:
_force_load_include_files(data)
for fpath in loaded_files:
if fpath == self._config_path.resolve():
discovered = yaml_util.discover_user_yaml_files(self._config_path)
self._secrets_paths.update(discovered.secrets)
config_resolved = self._config_path.resolve()
for fpath in discovered.files:
if fpath == config_resolved:
continue # Already added as config
if fpath.name in const.SECRETS_FILES:
self._secrets_paths.add(fpath)
self._add_file(fpath)
def _discover_component_files(self) -> None:
@@ -432,7 +412,7 @@ class ConfigBundleCreator:
@staticmethod
def _add_to_tar(tar: tarfile.TarFile, bf: BundleFile) -> None:
"""Add a BundleFile to the tar archive with deterministic metadata."""
with open(bf.source, "rb") as f:
with bf.source.open("rb") as f:
_add_bytes_to_tar(tar, bf.path, f.read())
@@ -623,57 +603,6 @@ def _add_bytes_to_tar(tar: tarfile.TarFile, name: str, data: bytes) -> None:
tar.addfile(info, io.BytesIO(data))
def _force_load_include_files(obj: Any, _seen: set[int] | None = None) -> None:
"""Recursively resolve any ``IncludeFile`` instances in a YAML tree.
Nested ``!include`` returns a deferred ``IncludeFile`` that is only
resolved during the substitution pass. During bundle discovery we need
the referenced files to actually load so the ``track_yaml_loads``
listener fires for them.
``IncludeFile`` instances with unresolved substitution variables in the
filename cannot be loaded — we skip and warn about those.
"""
if _seen is None:
_seen = set()
if isinstance(obj, yaml_util.IncludeFile):
if id(obj) in _seen:
return
_seen.add(id(obj))
if obj.has_unresolved_expressions():
_LOGGER.warning(
"Bundle: cannot resolve !include %s (referenced from %s) "
"with substitutions in path",
obj.file,
obj.parent_file,
)
return
try:
loaded = obj.load()
except EsphomeError as err:
_LOGGER.warning(
"Bundle: failed to load !include %s (referenced from %s): %s",
obj.file,
obj.parent_file,
err,
)
return
_force_load_include_files(loaded, _seen)
elif isinstance(obj, dict):
if id(obj) in _seen:
return
_seen.add(id(obj))
for value in obj.values():
_force_load_include_files(value, _seen)
elif isinstance(obj, (list, tuple)):
if id(obj) in _seen:
return
_seen.add(id(obj))
for item in obj:
_force_load_include_files(item, _seen)
def _resolve_include_path(include_path: Any) -> Path | None:
"""Resolve an include path to absolute, skipping system includes."""
if isinstance(include_path, str) and include_path.startswith("<"):

View File

@@ -0,0 +1,76 @@
"""Validated-config cache for the upload/logs fast path.
compile dumps the validated config to <data_dir>/storage/<file>.validated.yaml;
the next upload/logs for that YAML reuses it instead of running the full
read_config pipeline. YAML round-trip (yaml_util.dump/load_yaml) keeps
!lambda/!include/IDs/paths intact; mtime gates staleness.
"""
from __future__ import annotations
import logging
from pathlib import Path
from esphome.core import CORE
from esphome.helpers import write_file
from esphome.storage_json import StorageJSON, ext_storage_path
from esphome.types import ConfigType
_LOGGER = logging.getLogger(__name__)
def compiled_config_path(config_filename: str) -> Path:
"""Path to the cached validated config alongside the storage sidecar."""
return CORE.data_dir / "storage" / f"{config_filename}.validated.yaml"
def _cache_is_fresh(cache_path: Path, source_path: Path) -> bool:
"""True iff the cache file exists and isn't older than the source."""
try:
return cache_path.stat().st_mtime >= source_path.stat().st_mtime
except OSError:
return False
def save_compiled_config(config: ConfigType) -> None:
"""Write the validated-config cache. Always-write so mtime stays fresh.
Mode 0600 because show_secrets=True resolves !secret inline.
Failures are non-fatal: the fast path falls back to read_config.
"""
from esphome import yaml_util
try:
rendered = yaml_util.dump(config, show_secrets=True)
write_file(compiled_config_path(CORE.config_filename), rendered, private=True)
except Exception as err: # noqa: BLE001 # pylint: disable=broad-except
_LOGGER.debug("Skipping compiled config cache write: %s", err)
def load_compiled_config(conf_path: Path) -> ConfigType | None:
"""Load the cached validated config and apply storage metadata to CORE.
Returns None (caller falls back to read_config) when the cache is
missing, older than the source YAML, unparseable, or the sidecar
is incomplete.
"""
cache_path = compiled_config_path(conf_path.name)
if not _cache_is_fresh(cache_path, conf_path):
return None
from esphome import yaml_util
try:
config = yaml_util.load_yaml(cache_path, clear_secrets=False)
except Exception: # noqa: BLE001 # pylint: disable=broad-except
return None
storage = StorageJSON.load(ext_storage_path(conf_path.name))
if storage is None:
return None
# apply_to_core assumes a real compile wrote the sidecar; wizard-only
# sidecars leave both of these unset and can't drive upload/logs.
if not storage.core_platform and not storage.target_platform:
return None
storage.apply_to_core()
return config

View File

@@ -4,8 +4,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace a01nyub {
namespace esphome::a01nyub {
static const char *const TAG = "a01nyub.sensor";
@@ -42,5 +41,4 @@ void A01nyubComponent::check_buffer_() {
void A01nyubComponent::dump_config() { LOG_SENSOR("", "A01nyub Sensor", this); }
} // namespace a01nyub
} // namespace esphome
} // namespace esphome::a01nyub

View File

@@ -6,8 +6,7 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
namespace esphome {
namespace a01nyub {
namespace esphome::a01nyub {
class A01nyubComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
public:
@@ -23,5 +22,4 @@ class A01nyubComponent : public sensor::Sensor, public Component, public uart::U
std::vector<uint8_t> buffer_;
};
} // namespace a01nyub
} // namespace esphome
} // namespace esphome::a01nyub

View File

@@ -4,8 +4,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace a02yyuw {
namespace esphome::a02yyuw {
static const char *const TAG = "a02yyuw.sensor";
@@ -41,5 +40,4 @@ void A02yyuwComponent::check_buffer_() {
void A02yyuwComponent::dump_config() { LOG_SENSOR("", "A02yyuw Sensor", this); }
} // namespace a02yyuw
} // namespace esphome
} // namespace esphome::a02yyuw

View File

@@ -6,8 +6,7 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
namespace esphome {
namespace a02yyuw {
namespace esphome::a02yyuw {
class A02yyuwComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
public:
@@ -23,5 +22,4 @@ class A02yyuwComponent : public sensor::Sensor, public Component, public uart::U
std::vector<uint8_t> buffer_;
};
} // namespace a02yyuw
} // namespace esphome
} // namespace esphome::a02yyuw

View File

@@ -1,8 +1,7 @@
#include "a4988.h"
#include "esphome/core/log.h"
namespace esphome {
namespace a4988 {
namespace esphome::a4988 {
static const char *const TAG = "a4988.stepper";
@@ -51,5 +50,4 @@ void A4988::loop() {
this->step_pin_->digital_write(false);
}
} // namespace a4988
} // namespace esphome
} // namespace esphome::a4988

View File

@@ -4,8 +4,7 @@
#include "esphome/core/hal.h"
#include "esphome/components/stepper/stepper.h"
namespace esphome {
namespace a4988 {
namespace esphome::a4988 {
class A4988 : public stepper::Stepper, public Component {
public:
@@ -25,5 +24,4 @@ class A4988 : public stepper::Stepper, public Component {
HighFrequencyLoopRequester high_freq_;
};
} // namespace a4988
} // namespace esphome
} // namespace esphome::a4988

View File

@@ -1,8 +1,7 @@
#include "adalight_light_effect.h"
#include "esphome/core/log.h"
namespace esphome {
namespace adalight {
namespace esphome::adalight {
static const char *const TAG = "adalight_light_effect";
@@ -129,7 +128,7 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL
uint8_t *led_data = &frame_[6];
for (int led = 0; led < accepted_led_count; led++, led_data += 3) {
auto white = std::min(std::min(led_data[0], led_data[1]), led_data[2]);
auto white = std::min({led_data[0], led_data[1], led_data[2]});
it[led].set(Color(led_data[0], led_data[1], led_data[2], white));
}
@@ -138,5 +137,4 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL
return CONSUMED;
}
} // namespace adalight
} // namespace esphome
} // namespace esphome::adalight

View File

@@ -6,8 +6,7 @@
#include <vector>
namespace esphome {
namespace adalight {
namespace esphome::adalight {
class AdalightLightEffect : public light::AddressableLightEffect, public uart::UARTDevice {
public:
@@ -35,5 +34,4 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
std::vector<uint8_t> frame_;
};
} // namespace adalight
} // namespace esphome
} // namespace esphome::adalight

View File

@@ -17,8 +17,7 @@
#include <zephyr/drivers/adc.h>
#endif
namespace esphome {
namespace adc {
namespace esphome::adc {
#ifdef USE_ESP32
// clang-format off
@@ -162,5 +161,4 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif
};
} // namespace adc
} // namespace esphome
} // namespace esphome::adc

View File

@@ -1,8 +1,7 @@
#include "adc_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.common";
@@ -79,5 +78,4 @@ void ADCSensor::set_sample_count(uint8_t sample_count) {
void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
} // namespace adc
} // namespace esphome
} // namespace esphome::adc

View File

@@ -4,8 +4,7 @@
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.esp32";
@@ -364,7 +363,6 @@ float ADCSensor::sample_autorange_() {
return final_result;
}
} // namespace adc
} // namespace esphome
} // namespace esphome::adc
#endif // USE_ESP32

View File

@@ -11,8 +11,7 @@ ADC_MODE(ADC_VCC)
#include <Arduino.h>
#endif // USE_ADC_SENSOR_VCC
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.esp8266";
@@ -55,7 +54,6 @@ float ADCSensor::sample() {
return aggr.aggregate() / 1024.0f;
}
} // namespace adc
} // namespace esphome
} // namespace esphome::adc
#endif // USE_ESP8266

View File

@@ -3,8 +3,7 @@
#include "adc_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.libretiny";
@@ -48,7 +47,6 @@ float ADCSensor::sample() {
return aggr.aggregate() / 1000.0f;
}
} // namespace adc
} // namespace esphome
} // namespace esphome::adc
#endif // USE_LIBRETINY

View File

@@ -15,8 +15,7 @@
#define PICO_VSYS_PIN 29 // NOLINT(cppcoreguidelines-macro-usage)
#endif
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.rp2040";
@@ -98,7 +97,6 @@ float ADCSensor::sample() {
return aggr.aggregate() * 3.3f / 4096.0f * coeff;
}
} // namespace adc
} // namespace esphome
} // namespace esphome::adc
#endif // USE_RP2040

View File

@@ -5,8 +5,7 @@
#include "hal/nrf_saadc.h"
namespace esphome {
namespace adc {
namespace esphome::adc {
static const char *const TAG = "adc.zephyr";
@@ -202,6 +201,5 @@ float ADCSensor::sample() {
return val_mv / 1000.0f;
}
} // namespace adc
} // namespace esphome
} // namespace esphome::adc
#endif

View File

@@ -1,8 +1,7 @@
#include "adc128s102.h"
#include "esphome/core/log.h"
namespace esphome {
namespace adc128s102 {
namespace esphome::adc128s102 {
static const char *const TAG = "adc128s102";
@@ -28,5 +27,4 @@ uint16_t ADC128S102::read_data(uint8_t channel) {
return digital_value;
}
} // namespace adc128s102
} // namespace esphome
} // namespace esphome::adc128s102

View File

@@ -4,8 +4,7 @@
#include "esphome/core/hal.h"
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace adc128s102 {
namespace esphome::adc128s102 {
class ADC128S102 : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
@@ -19,5 +18,4 @@ class ADC128S102 : public Component,
uint16_t read_data(uint8_t channel);
};
} // namespace adc128s102
} // namespace esphome
} // namespace esphome::adc128s102

View File

@@ -2,8 +2,7 @@
#include "esphome/core/log.h"
namespace esphome {
namespace adc128s102 {
namespace esphome::adc128s102 {
static const char *const TAG = "adc128s102.sensor";
@@ -18,5 +17,4 @@ void ADC128S102Sensor::dump_config() {
float ADC128S102Sensor::sample() { return this->parent_->read_data(this->channel_); }
void ADC128S102Sensor::update() { this->publish_state(this->sample()); }
} // namespace adc128s102
} // namespace esphome
} // namespace esphome::adc128s102

View File

@@ -7,8 +7,7 @@
#include "../adc128s102.h"
namespace esphome {
namespace adc128s102 {
namespace esphome::adc128s102 {
class ADC128S102Sensor : public PollingComponent,
public Parented<ADC128S102>,
@@ -24,5 +23,4 @@ class ADC128S102Sensor : public PollingComponent,
protected:
uint8_t channel_;
};
} // namespace adc128s102
} // namespace esphome
} // namespace esphome::adc128s102

View File

@@ -1,8 +1,7 @@
#include "addressable_light_display.h"
#include "esphome/core/log.h"
namespace esphome {
namespace addressable_light {
namespace esphome::addressable_light {
static const char *const TAG = "addressable_light.display";
@@ -66,5 +65,4 @@ void HOT AddressableLightDisplay::draw_absolute_pixel_internal(int x, int y, Col
this->addressable_light_buffer_[y * this->get_width_internal() + x] = color;
}
}
} // namespace addressable_light
} // namespace esphome
} // namespace esphome::addressable_light

View File

@@ -7,8 +7,7 @@
#include <vector>
namespace esphome {
namespace addressable_light {
namespace esphome::addressable_light {
class AddressableLightDisplay : public display::DisplayBuffer {
public:
@@ -61,5 +60,4 @@ class AddressableLightDisplay : public display::DisplayBuffer {
optional<uint32_t> last_effect_index_;
optional<std::function<int(int, int)>> pixel_mapper_f_;
};
} // namespace addressable_light
} // namespace esphome
} // namespace esphome::addressable_light

View File

@@ -1 +0,0 @@
CODEOWNERS = ["@kpfleming"]

View File

@@ -13,8 +13,7 @@
#include <cinttypes>
namespace esphome {
namespace ade7880 {
namespace esphome::ade7880 {
static const char *const TAG = "ade7880";
@@ -88,14 +87,24 @@ void ADE7880::update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_
sensor->publish_state(f(val));
}
template<typename F>
void ADE7880::update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) {
if (sensor == nullptr) {
void ADE7880::update_active_energy_(PowerChannel *channel, uint16_t a_register) {
if (channel->forward_active_energy == nullptr && channel->reverse_active_energy == nullptr) {
return;
}
float val = this->read_s32_register16_(a_register);
sensor->publish_state(f(val));
// The ADE7880 has no separate forward/reverse active energy accumulators. The xWATTHR registers
// accumulate signed energy since the last read (positive = imported/forward, negative = exported/
// reverse), so split the value by sign into the forward and reverse running totals.
float val = this->read_s32_register16_(a_register) / 14400.0f;
if (val >= 0.0f) {
if (channel->forward_active_energy != nullptr) {
channel->forward_active_energy->publish_state(channel->forward_active_energy_total += val);
}
} else {
if (channel->reverse_active_energy != nullptr) {
channel->reverse_active_energy->publish_state(channel->reverse_active_energy_total -= val);
}
}
}
void ADE7880::update() {
@@ -118,12 +127,7 @@ void ADE7880::update() {
this->update_sensor_from_s24zp_register16_(chan->apparent_power, AVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, APF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, AFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, ARWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
this->update_active_energy_(chan, AWATTHR);
}
if (this->channel_b_ != nullptr) {
@@ -134,12 +138,7 @@ void ADE7880::update() {
this->update_sensor_from_s24zp_register16_(chan->apparent_power, BVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, BPF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, BFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, BRWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
this->update_active_energy_(chan, BWATTHR);
}
if (this->channel_c_ != nullptr) {
@@ -150,12 +149,7 @@ void ADE7880::update() {
this->update_sensor_from_s24zp_register16_(chan->apparent_power, CVA, [](float val) { return val / 100.0f; });
this->update_sensor_from_s16_register16_(chan->power_factor, CPF,
[](float val) { return std::abs(val / -327.68f); });
this->update_sensor_from_s32_register16_(chan->forward_active_energy, CFWATTHR, [&chan](float val) {
return chan->forward_active_energy_total += val / 14400.0f;
});
this->update_sensor_from_s32_register16_(chan->reverse_active_energy, CRWATTHR, [&chan](float val) {
return chan->reverse_active_energy_total += val / 14400.0f;
});
this->update_active_energy_(chan, CWATTHR);
}
ESP_LOGD(TAG, "update took %" PRIu32 " ms", millis() - start);
@@ -313,5 +307,4 @@ void ADE7880::reset_device_() {
this->store_.reset_pending = true;
}
} // namespace ade7880
} // namespace esphome
} // namespace esphome::ade7880

View File

@@ -16,8 +16,7 @@
#include "ade7880_registers.h"
namespace esphome {
namespace ade7880 {
namespace esphome::ade7880 {
struct NeutralChannel {
void set_current(sensor::Sensor *sens) { this->current = sens; }
@@ -106,7 +105,8 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
// the callable will be passed a 'float' value and is expected to return a 'float'
template<typename F> void update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
template<typename F> void update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
template<typename F> void update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
void update_active_energy_(PowerChannel *channel, uint16_t a_register);
void reset_device_();
@@ -125,5 +125,4 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
void write_u32_register16_(uint16_t a_register, uint32_t value);
};
} // namespace ade7880
} // namespace esphome
} // namespace esphome::ade7880

Some files were not shown because too many files have changed in this diff Show More