Commit Graph

3812 Commits

Author SHA1 Message Date
J. Nick Koston 191115bf18 Merge remote-tracking branch 'origin/ota-wakeable-delay-yield' into integration 2026-04-27 07:55:22 -05:00
J. Nick Koston ee0da8a482 Merge remote-tracking branch 'origin/wifi_phy_mode_esp8266' into integration 2026-04-27 07:50:19 -05:00
J. Nick Koston e232325a33 [wifi] Add phy_mode option for ESP8266 2026-04-27 07:43:21 -05:00
J. Nick Koston 24a0db1029 Merge remote-tracking branch 'origin/test-cover-control-action' into integration 2026-04-27 06:46:18 -05:00
J. Nick Koston 5f15dc9ba4 Merge remote-tracking branch 'origin/test-climate-control-action' into integration 2026-04-27 06:46:14 -05:00
J. Nick Koston d26e29d89c Merge remote-tracking branch 'origin/light-toggle-action-constexpr-template' into integration 2026-04-27 06:46:06 -05:00
J. Nick Koston 4ed7956094 Merge remote-tracking branch 'origin/light-dim-relative-constexpr-template' into integration 2026-04-27 06:46:00 -05:00
J. Nick Koston 1135eeaf99 Merge remote-tracking branch 'origin/cover-action-bitmask' into integration 2026-04-27 06:45:48 -05:00
J. Nick Koston a46d7e0a6a [cover] Also exercise cover.template.publish with state: alias 2026-04-27 06:42:15 -05:00
J. Nick Koston c60cf7f5b7 [climate] Add climate.control coverage to component tests via thermostat 2026-04-27 06:21:56 -05:00
J. Nick Koston 50b0474d60 [cover] Reword: generic coverage, not bitmask-specific 2026-04-27 06:20:43 -05:00
J. Nick Koston 53454adc40 [cover] Add cover.control / cover.template.publish coverage to template tests 2026-04-27 06:19:39 -05:00
J. Nick Koston 6770a6b87f [cover] Address Copilot review on integration test fixture and macro comments 2026-04-27 05:39:21 -05:00
J. Nick Koston 65b5615a31 [light] Use InitialStateHelper in DimRelativeAction integration test 2026-04-27 05:10:02 -05:00
J. Nick Koston 83f83c96a8 [light] Use InitialStateHelper in ToggleAction integration test 2026-04-27 05:09:27 -05:00
J. Nick Koston a532f0adc9 [cover] Use InitialStateHelper in integration test 2026-04-27 05:08:08 -05:00
J. Nick Koston 2eac9f5121 [light] Add integration test for DimRelativeAction 2026-04-27 05:05:00 -05:00
J. Nick Koston e9ced485ea [light] Add integration test for ToggleAction 2026-04-27 05:04:28 -05:00
J. Nick Koston 3522eef8ee [cover] Add integration test for ControlAction/CoverPublishAction 2026-04-27 05:02:58 -05:00
J. Nick Koston 35163e5bca Merge branch 'inline-continuation-actions' into integration 2026-04-26 22:22:06 -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
J. Nick Koston 13250897ad [light] Add dim_relative test case with transition_length 2026-04-26 21:47:52 -05:00
J. Nick Koston 84aa308557 Merge remote-tracking branch 'upstream-ssh/analyze-memory-main-cpp-attribution' into integration 2026-04-26 15:12:28 -05:00
J. Nick Koston 82ba873ea7 [analyze_memory] Attribute main.cpp setup()/loop() to esphome core
The generated src/main.cpp.o was being skipped by _scan_source_symbols
(which only walked src/esphome/) and _source_file_to_component had no
rule for it. As a result setup()/loop() fell through to the
"app_framework" heuristic in const.py instead of being counted as
[esphome]core, both via the nm scan path and the linker map path.

Scan all of src/ and recognize .../src/main.cpp.o as core.
2026-04-26 15:10:48 -05:00
J. Nick Koston 97e8417ac6 Merge branch 'combine-entity-register-clean' into integration 2026-04-26 14:38:54 -05:00
J. Nick Koston 61976ca117 Merge branch 'register-component-source-overload' into integration 2026-04-26 14:38:50 -05:00
J. Nick Koston 01e0cda3c0 [core] Combine entity register + configure_entity_ into one call
Add 4-arg overloads to App.register_<entity>() that call configure_entity_()
and push_back in a single function. Codegen defers App.register_<entity>(var)
emission until finalize_entity_strings(), which then emits a single combined
App.register_<entity>(var, name, hash, packed) call instead of the previous
two-statement pair (App.register_X(var); var->configure_entity_(...)).

Apollo R-PRO-1 (ESP32-S3 IDF, 122 components, 164 entities), same toolchain:
  text:     -1248 bytes
  main.cpp: -164 lines

No behavior change. configure_entity_ remains protected on EntityBase; the
Application class is now a friend so the new overloads can call it.
2026-04-26 14:37:37 -05:00
J. Nick Koston e1ca77e025 Update tests for combined register_component_ call 2026-04-26 14:19:43 -05:00
J. Nick Koston 0fadf1470c Merge remote-tracking branch 'origin/external-files-content-error' into integration
# Conflicts:
#	tests/unit_tests/test_external_files.py
2026-04-26 10:40:14 -05:00
J. Nick Koston 6e13182120 Address Copilot review on PR #16023
Replace `type(mock_response).content = property(...)` with a tiny
_BodyReadErrorResponse stub class. The previous form mutates
MagicMock's class globally, which can leak into every other
MagicMock-using test in this file.
2026-04-26 10:39:29 -05:00
J. Nick Koston a94290c08c Merge remote-tracking branch 'origin/external-files-content-error' into integration
# Conflicts:
#	esphome/external_files.py
#	tests/unit_tests/test_external_files.py
2026-04-26 10:36:05 -05:00
J. Nick Koston 24a3c2202f [core] Catch body-read errors in download_content
`requests.Response.content` reads the body lazily, so chunked-decode,
gzip-decode, and mid-stream connection drops all surface as
RequestException subclasses on first access -- not from requests.get
itself. The previous code accessed `.content` outside the surrounding
try/except, so any of those (rare but real) errors would propagate
out of download_content instead of falling back to the cached file
or raising the user-friendly cv.Invalid.

Move `data = req.content` inside the try block so the existing error
path handles it. Two new tests cover the with-cache and no-cache
branches using a `ChunkedEncodingError` injected on `.content`.
2026-04-26 10:35:06 -05:00
J. Nick Koston b22e46f090 Merge remote-tracking branch 'origin/external-files-etag' into integration 2026-04-26 10:16:00 -05:00
J. Nick Koston b303cc68f6 Cover the two _write_etag error branches
EsphomeError from write_file and OSError from os.utime are both
swallowed and logged at DEBUG; add tests so neither branch can regress
silently.
2026-04-26 10:15:54 -05:00
J. Nick Koston af52f6a170 Merge remote-tracking branch 'origin/external-files-etag' into integration
# Conflicts:
#	tests/unit_tests/test_external_files.py
2026-04-26 10:10:11 -05:00
J. Nick Koston b78bca0dc7 Simplify _read_etag, walrus the etag/new_etag binds, fixturize requests + helper patches
- _read_etag collapses into a single try/except that handles both stat
  and read failures (and the unlink) uniformly.
- _mtime_seconds() helper compares mtimes at whole-second resolution
  instead of nanoseconds. Sub-second precision varies by filesystem
  (FAT does 2s, NTFS 100ns, APFS/ext4 ns); whole seconds is the only
  resolution every supported filesystem can preserve through a
  set+read round-trip.
- has_remote_file_changed: walrus-assign `etag` and `new_etag` instead
  of an explicit binding + immediate check.
- New test fixtures `mock_requests_head`, `mock_requests_get`,
  `mock_has_remote_file_changed`, `mock_write_file` replace the
  per-test `@patch(...)` decorator stacks. Tests are simpler and the
  fixtures can be reused by future tests in the file.
2026-04-26 10:09:38 -05:00
J. Nick Koston 1cecb98f56 Merge remote-tracking branch 'origin/external-files-parallel' into integration 2026-04-26 10:03:03 -05:00
J. Nick Koston 2def20c646 Use partial() for download_web_files_in_config call sites; collapse dedup loop into a dict comp
- Both audio_file and speaker.media_player now use functools.partial to
  bind path_for=_compute_local_file_path instead of an inline lambda.
- download_content_many's dedup loop becomes a dict comprehension.
  Last-URL wins now (dict-comp semantics) instead of first-URL; in
  practice duplicate paths only arise when the URL itself is duplicated,
  so the choice is meaningless. Test updated accordingly.
2026-04-26 10:02:44 -05:00
J. Nick Koston 9153c1be67 Merge remote-tracking branch 'origin/external-files-etag' into integration 2026-04-26 09:58:29 -05:00
J. Nick Koston fea64833b0 Merge remote-tracking branch 'origin/external-files-parallel' into integration
# Conflicts:
#	tests/unit_tests/test_external_files.py
2026-04-26 09:58:27 -05:00
J. Nick Koston 267590fc36 Extract mock_download_content[_many] fixtures in test_external_files 2026-04-26 09:57:23 -05:00
J. Nick Koston a877acf1d1 Address Copilot review on PR #16021
- download_content_many now de-duplicates by `path` so two callers
  asking for the same cache file (e.g. the same URL referenced twice
  in a config) can't race on download_content's non-atomic write. When
  duplicates are present, the first-seen URL for that path wins.
- Clamp `max_workers` to at least 1 so an invalid caller value can't
  raise ValueError out of ThreadPoolExecutor.
2026-04-26 09:55:27 -05:00
J. Nick Koston da322356e1 Address Copilot review on PR #16020
- _write_etag: suppress OSError (not just FileNotFoundError) when removing
  a stale sidecar -- ETag persistence is best-effort and a permission
  error there must not abort an otherwise-successful download.
- Atomic-write test: patch write_file directly so the failure happens
  inside the helper that does the rename, instead of before
  download_content even calls it.
2026-04-26 09:54:38 -05:00
J. Nick Koston eb3bf5baed Merge remote-tracking branch 'origin/external-files-parallel' into integration
# Conflicts:
#	esphome/external_files.py
2026-04-26 09:53:29 -05:00
J. Nick Koston 54493faafc Fix download_web_files_in_config tests for generator argument 2026-04-26 09:53:07 -05:00
J. Nick Koston 540696282b Hoist duplicated _download_all_web_files into external_files.download_web_files_in_config
audio_file and speaker.media_player had byte-identical helpers that
collected web URLs from a list-of-file-configs and handed them to
download_content_many. Move that logic into external_files as
`download_web_files_in_config(config, path_for)` -- callers only have
to pass the per-component cache-path callback now.
2026-04-26 09:52:29 -05:00
J. Nick Koston 7983ebf54a Merge remote-tracking branch 'origin/external-files-etag' into integration 2026-04-26 09:42:36 -05:00
J. Nick Koston 5ae259ccba Sync ETag sidecar mtime with cache file; treat mismatched sidecars as stale
The ETag sidecar describes a specific snapshot of the cache file. If the
cache file is replaced or edited out-of-band (manual edit, restore from
backup, another tool overwriting it), the sidecar's recorded ETag no
longer matches the bytes on disk -- using it would cause the server to
return 304 and we'd serve the wrong content from cache.

- _write_etag now os.utime()'s the sidecar to share the cache file's
  st_mtime_ns immediately after writing it.
- _read_etag compares the two mtimes; if they don't match it returns
  None and removes the sidecar so subsequent calls don't re-check it.
2026-04-26 09:41:20 -05:00