Commit Graph

14966 Commits

Author SHA1 Message Date
J. Nick Koston
5a7b1c411e [cli] DRY up --prebuilt-dir helpers
Two small simplifications surfaced by re-reading the diff with a 'is
this DRY?' lens:

- Extract _missing_prebuilt_flash_tool(): the
  _ensure_platform_packages_for_prebuilt_upload helper had two
  near-identical 'if platform check; if finder() is not None return 0;
  tool_label = ...' blocks. Lift the platform->(tool_name) selection
  into a tiny helper so the early-return is one line and the install
  body is no longer interleaved with the platform dispatch.

- Collapse the two near-duplicate 'firmware not found' return points in
  upload_using_picotool. Both branches just selected an error message
  and returned 1; reorder so the message selection happens first and
  there's a single 'return 1'.

No behavior change; pure refactor. 587 unit tests pass.

Issue: esphome/device-builder#572
2026-05-11 16:00:42 -05:00
J. Nick Koston
bcac422e9e [cli] Address self-review on --prebuilt-dir
- CORE.firmware_bin priority is now platform-aware: RP2040 + libretiny
  prefer firmware.uf2 over firmware.bin (picotool / ltchiptool need the
  UF2 header for address/family info); ESP* prefer firmware.bin. The
  prior code returned .bin first for all platforms, which would have
  silently flashed the wrong artifact on RP2040 if a hand-staged dir
  shipped both files. New tests guard both directions.

- _rp2040_serial_reset_to_bootsel: check picotool exists *before*
  triggering the 1200bps touch. If picotool is missing, the touch
  would have left the device stranded in BOOTSEL with nothing able to
  flash it; with this order the device stays on the old firmware and
  can be retried.

- upload_using_ltchiptool: error message now mentions both firmware.uf2
  and firmware.bin since CORE.firmware_bin resolves either.

- prepare_platform_for_upload: return type tightened to int (capture_stdout
  is hardcoded False; assert the run helper returns int so a future caller
  that flips capture_stdout fails loudly instead of silently treating a
  string as success). Caller in __main__.py is now a one-liner.

- _load_idedata: narrative comment in the prebuilt branch shortened.
  _resolve_prebuilt_idedata_paths docstring now notes the
  POSIX-absolute-on-Windows quirk ("/foo/bar" is rooted but not absolute
  on win32; hand-staged dirs need OS-appropriate absolute paths).

- New defensive-coverage tests: _resolve_prebuilt_idedata_paths with
  missing prog_path, no extra section, empty flash_images list.

Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
2026-05-11 13:32:36 -05:00
J. Nick Koston
c870ad328e [cli] Fix Windows pytest: use platform-absolute path in --prebuilt-dir test
The 'absolute paths pass through unchanged' test for _load_idedata
hardcoded a POSIX-style absolute path ('/somewhere/else/bootloader.bin').
On Windows, Path.is_absolute() returns False for that shape -- absolute
paths there require a drive letter -- so _resolve_prebuilt_idedata_paths
classified it as relative and prepended CORE.prebuilt_dir, breaking the
test's assertion.

Replace the hardcoded POSIX path with a tmp_path-rooted one so it's
platform-absolute on every runner. No production code change; this is a
test-only fix surfaced by the windows-latest pytest matrix on PR #16348.

Note: the macOS 3.14 failure on the same CI run is a flaky timing test
(tests/dashboard/test_web_server.py::test_dashboard_subscriber_entries_update_interval,
50ms sleep expecting 2+ iterations at 10ms) unrelated to this PR.

Issue: esphome/device-builder#572
2026-05-11 11:09:36 -05:00
J. Nick Koston
1ba8b838da [cli] Address Copilot review on --prebuilt-dir
- get_ltchiptool_path: use 'Scripts/' on Windows, 'bin/' elsewhere when
  falling back to PlatformIO's libretiny penv. CPython venvs put scripts
  under Scripts/ on win32 and bin/ on POSIX; the prior hardcoded 'bin'
  would never have found ltchiptool on Windows.
- _load_idedata: wrap json.loads on the prebuilt idedata.json in a
  try/except and re-raise as EsphomeError with a one-line diagnostic so
  the failure mode is a clean error instead of an unhandled
  JSONDecodeError stack trace. Update the surrounding comment to match
  the new behavior.
- CORE.prebuilt_dir docstring: drop the dead 'docs/architecture/...'
  pointer (no docs/ tree in this repo); point at esphome-docs#6600 and
  device-builder#572 instead.

New regression test:
- test_load_idedata_prebuilt_malformed_json_raises_esphomeerror

Updated test:
- test_get_ltchiptool_path_pio_penv now uses Scripts/ on win32 to match
  the new platform-aware lookup.

Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
2026-05-11 10:58:17 -05:00
J. Nick Koston
956c2a9780 Merge remote-tracking branch 'upstream/dev' into core-prebuilt-dir-upload
# Conflicts:
#	esphome/__main__.py
2026-05-11 10:55:31 -05: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
J. Nick Koston
5cc7719ae4 [cli] Use pio run -t idedata to set up libretiny penv on cold hosts
The prior commit invoked 'pio pkg install' for the on-demand prep step,
which installs the libretiny platform package but does NOT recreate the
~/.platformio/penv/.libretiny/ virtualenv -- that's set up by libretiny's
ConfigurePythonVenv SCons step, which only fires during 'pio run'. So a
cold host (penv missing) still failed to find ltchiptool after the install
returned 'Already up-to-date'.

Wet test against bw15-device.yaml on a host with the libretiny penv
deleted:
  esphome upload bw15-device.yaml --device /dev/null --prebuilt-dir ...
  INFO ltchiptool not found on this host; installing the PlatformIO
       rtl87xx platform package ...
  Resolving bw15-device dependencies...
  Already up-to-date.
  ERROR ltchiptool not found. ...

Replace pkg install with 'pio run -t idedata'. The idedata target runs
SConscript without the actual compile target, so penv creation (libretiny)
and tool-package install (RP2040) happen as side effects of the SCons
configure phase -- but the build itself is skipped. Cost is a few seconds
of SCons configure, paid once per cold host.

Rename run_pkg_install -> prepare_platform_for_upload to match the new
semantics.

Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
2026-05-11 00:30:06 -05: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
J. Nick Koston
aab7177f07 [cli] Add write_cpp-failure test for --prebuilt-dir pkg-install prep
Symmetric with test_upload_program_prebuilt_dir_pkg_install_failure_aborts_upload:
covers the early-return path when write_cpp fails (codegen error, disk
full, validation regression) before pkg install runs. Closes the
coverage matrix for _ensure_platform_packages_for_prebuilt_upload's
two failure points.

Issue: esphome/device-builder#572
2026-05-10 23:58:16 -05:00
Jesse Hills
c4e85fbfc1 [ci] sync-device-classes: mint least-privilege App token (#16350) 2026-05-11 16:57:10 +12:00
J. Nick Koston
7674170600 [cli] Auto-install PlatformIO platform when --prebuilt-dir needs its flash tool
Revert ltchiptool as a hard dependency so the vast majority of ESPHome
users (ESP32 / ESP8266 / nRF52 OTA) don't pay for libretiny tooling.
Instead, on-demand install just the PlatformIO platform package when a
--prebuilt-dir upload needs a flash tool that isn't on disk yet.

Mechanism: when upload_program receives --prebuilt-dir for a libretiny
or RP2040 target and the corresponding flash tool (ltchiptool / picotool)
isn't found by get_ltchiptool_path / _find_picotool, run the same prep
that 'esphome compile' would (write_cpp + write platformio.ini), then
invoke 'pio pkg install -e <env>' instead of 'pio run'. PlatformIO
downloads the platform without compiling, the flash tool ends up on disk,
and the upload dispatch picks it up on the next lookup.

After install, the tool path lookups (PATH + PIO penv for ltchiptool,
PIO packages dir for picotool) succeed and the upload helper takes over.
ESP32 / ESP8266 / nRF52 paths are unchanged (esptool is already bundled
in requirements.txt; smpclient too for nRF52 mcumgr).

Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
2026-05-10 23:48:05 -05:00
J. Nick Koston
758189fe56 [deps] Bundle ltchiptool for libretiny prebuilt-dir uploads
`esphome upload --prebuilt-dir` on a libretiny device routes through
ltchiptool to bypass the PlatformIO build-tree requirement. On hosts
that have never compiled a libretiny config locally (the dashboard's
transparent-install use case) the libretiny PlatformIO platform's
penv at ~/.platformio/penv/.libretiny/bin/ltchiptool doesn't exist
yet, leaving the upload to fail with an actionable but unwelcome
"install ltchiptool" hint.

Bundle ltchiptool as a direct dependency, mirroring esptool which is
already shipped even though only ESP users need it. `pip install
esphome` is now sufficient for libretiny serial uploads from a
prebuilt artifact set; get_ltchiptool_path's PATH lookup picks up
the pip-installed binary first, with the PIO penv fallback still in
place for environments that vendor esphome without the extra.

Issue: esphome/device-builder#572
Issue: esphome/device-builder#570
2026-05-10 23:40:56 -05:00
J. Nick Koston
f4607cb521 [cli] Accept basenames in prebuilt idedata.json
The dashboard's source-routed runner ships idedata.json with bare
basenames in prog_path and extra.flash_images[*].path (the receiver's
build-host absolute paths don't resolve on the offloader, and the
in-memory Web Serial consumer keys by basename). Without this change,
the dashboard would have to write a fresh idedata.json into the staging
tmpdir on every install just to flip basenames to absolute paths.

Resolve relative paths in the prebuilt idedata against CORE.prebuilt_dir
so both the dashboard's wire format and a hand-built directory with
absolute paths work. cc_path is left alone because it points at a
PlatformIO toolchain binary outside the prebuilt dir; the offloader's
own PIO install provides the matching binary.

Issue: esphome/device-builder#570
Issue: esphome/device-builder#572
2026-05-10 23:21:23 -05:00
J. Nick Koston
0adfd08270 [cli] Address review feedback on --prebuilt-dir
- upload_using_ltchiptool: rename unused config arg to _config and note
  the signature parity with upload_using_platformio/upload_using_picotool
  so dispatch stays symmetric.
- upload_program: explicit exit_code = 1 when _rp2040_serial_reset_to_bootsel
  fails, instead of relying on the function-level default.
- upload_using_picotool: distinct error message for the prebuilt-dir case
  that names both candidates (idedata ELF + prebuilt firmware) instead of
  just pointing at the missing ELF.
- _load_idedata: document the prebuilt-dir idedata.json contract more
  loudly (absolute paths under prebuilt_dir, no schema validation, dashboard
  owns the rewrites).
- --prebuilt-dir help text: drop the placeholder docs URL; describe the
  dashboard-internal intent inline so users who hit the flag in --help
  understand they don't want it.
- New test: upload_using_esptool with ESP-IDF toolchain + --prebuilt-dir
  uses <prebuilt-dir>/firmware.factory.bin at offset 0x0.

Issue: esphome/device-builder#572
2026-05-10 23:18:48 -05:00
J. Nick Koston
d96ad02b9f [nrf52] Honor --prebuilt-dir for mcumgr/BLE OTA uploads
nRF52 has its own upload_program that runs before the default dispatch
in esphome.__main__. The mcumgr/BLE OTA path reads the MCUboot-signed
update image from CORE.relative_pioenvs_path(name, 'zephyr',
'app_update.bin'), which assumes a local Zephyr build tree.

Consult CORE.prebuilt_artifact_path('app_update.bin') first so the
dashboard's transparent BLE install on a Bluetooth proxy can flash a
prebuilt update image without compiling locally.

Serial uploads on non-MCUboot bootloaders still go through
adafruit-nrfutil via _upload_using_platformio and are out of scope here;
they need their own bypass to work with --prebuilt-dir (tracked
separately).

Issue: esphome/device-builder#572
2026-05-10 23:07:04 -05:00
J. Nick Koston
a6a0a404ae [cli] Flash RP2040 serial prebuilt-dir uploads via 1200bps touch + picotool
Mirror the libretiny/ltchiptool shape for RP2040 serial when
--prebuilt-dir is set: open the user-supplied serial port at 1200 baud
(arduino-pico's USB CDC interprets the open/close as a request to reboot
into BOOTSEL), poll picotool until the BOOTSEL device shows up on the
USB bus, then dispatch to upload_using_picotool with the prebuilt .uf2.

This removes the last path that required --prebuilt-dir to contain a
platformio.ini + .pioenvs/<name>/ tree, so upload_using_platformio is
now only invoked when no prebuilt dir is set (i.e. the existing
compile+upload flow on a developer machine).

Issue: esphome/device-builder#572
2026-05-10 23:04:18 -05:00
J. Nick Koston
b8336cddf2 [cli] Flash libretiny prebuilt-dir uploads via ltchiptool
The libretiny upload path on `upload_program` SERIAL dispatch re-invokes
PlatformIO (`pio run -t upload -t nobuild`), which needs a full build
tree and `platformio.ini`. That makes it incompatible with a dashboard
that only has prebuilt artifacts.

Bypass PlatformIO for the libretiny+SERIAL+--prebuilt-dir case by calling
`ltchiptool flash write -d <port> <firmware.uf2>` directly. The .uf2
encodes the chip family in its header so no extra config is needed.

ltchiptool ships with the libretiny PlatformIO platform under
~/.platformio/penv/.libretiny/bin/ltchiptool; `get_ltchiptool_path()`
prefers PATH first (pip install ltchiptool) and falls back to the
PlatformIO penv. Without --prebuilt-dir the existing PlatformIO path
remains in place, so this is purely additive.

Issue: esphome/device-builder#572
2026-05-10 22:52:17 -05:00
J. Nick Koston
255d4c6b65 [cli] Add esphome upload --prebuilt-dir <path>
Adds a --prebuilt-dir flag to esphome upload that points the per-platform
upload helpers at a directory of prebuilt artifacts shipped from a paired
build server, instead of re-deriving paths from the local build tree.

Covers every upload-dispatch shape:
- ESP32 / ESP8266 serial (esptool) reads firmware.bin + extras via the
  prebuilt idedata.json the dashboard ships next to the artifacts.
- ESP32 / ESP8266 OTA (native API + web_server) reads CORE.firmware_bin,
  CORE.partition_table_bin and CORE.bootloader_bin which now consult the
  prebuilt-dir first.
- RP2040 BOOTSEL (picotool) falls back from the idedata ELF (absent in
  the flat layout) to the prebuilt firmware.uf2.
- RP2040 serial / libretiny serial / OTA (PlatformIO upload -t nobuild)
  point platformio at the prebuilt build tree via CORE.build_path so the
  -t upload -t nobuild path finds platformio.ini and .pioenvs/<name>/.

Issue: esphome/device-builder#572
2026-05-10 22:28:19 -05: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