Commit Graph
727 Commits
Author SHA1 Message Date
J. Nick Koston 0c3682124d Merge remote-tracking branch 'upstream/cli-from-storage-json' into integration 2026-05-12 17:54:11 -05:00
J. Nick Koston b8c2d66c0e [core] Assert on cache-hit log line so coverage is unambiguous 2026-05-12 17:51:49 -05:00
J. Nick Koston bcd07abb5f [core] Fix flake8 D403 in test docstring 2026-05-12 17:48:44 -05:00
J. Nick Koston 1902519f37 [core] Fix Windows path separator in cache path test 2026-05-12 17:48:17 -05:00
J. Nick Koston e7af2aaf9b [core] Address review: secrets perms, mtime freshness, substitution regression, tests
- save_compiled_config: write the cache with mode 0600 (the YAML
  contains resolved secrets) and always rewrite so mtime advances
  even when content is unchanged. Previously write_file_if_changed
  could leave mtime pinned behind a whitespace YAML edit, locking
  the fast path to 'stale'.
- __main__: skip the fast path when -s overrides are passed. The
  cache was written against the previous substitution set;
  reusing it would silently ignore the new values.
- Add tests for save_compiled_config (write + swallow-errors), the
  wizard-only sidecar fallback, and the substitution-skip branch.
- Trim docstrings/comments throughout.
2026-05-12 17:39:43 -05:00
J. Nick Koston a19e817d28 [core] Shrink apply_to_core to what upload/logs actually read
apply_to_core was over-populating: it restored friendly_name,
loaded_integrations, and loaded_platforms even though every
consumer of those three lives inside a component validator
(esp32_camera, esp32, deep_sleep, zigbee, lvgl, zephyr_mcumgr),
and the whole point of the fast path is to skip validation.

Drop them. CORE.__init__ already leaves all three at safe defaults
(None / empty set) for any incidental reader.

What's left is exactly what upload/logs walk:

  - CORE.name (api.client.run_logs, firmware_bin path, mDNS)
  - CORE.build_path (firmware_bin / partition_table_bin / bootloader_bin)
  - CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] (module dispatch, .is_esp32 etc)
  - CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] (.is_arduino, firmware_bin branch)

Method body shrinks from 9 statements to 4; setdefault + two
conditional inserts collapse into one dict literal; the
function-local import moves to module top. Drift surface drops
from 7 paired fields to 4. The wizard-only-sidecar None case is
gated once at the load_compiled_config boundary so apply_to_core
no longer has to defend against it.
2026-05-12 17:29:29 -05:00
J. Nick Koston 5709ade577 Revert "[core] Derive CORE state from cached config dict, drop apply_to_core"
This reverts commit cc6245b876.
2026-05-12 15:54:23 -05:00
J. Nick Koston cc6245b876 [core] Derive CORE state from cached config dict, drop apply_to_core
`StorageJSON.apply_to_core` was the inverse of `from_esphome_core`:
two enumerations of the same fields that had to stay in sync. When a
new CORE attribute joined the validation pipeline, both lists needed
an update.

Replace it with `_populate_core_from_validated_config(config)` in
`compiled_config.py` that reads the cached config dict directly --
same source `read_config` writes into during validation, no separate
sidecar schema. The fast path no longer touches StorageJSON at all;
the sidecar stays in place for the dashboard's existing use.

Drift surface shrinks to: name/friendly_name/build_path under the
esphome block (config schema is stable) + target_platform discovered
via `_is_target_platform` (the canonical detector) + framework via
the `<platform>.framework.type` convention every platform component
already follows.
2026-05-12 15:53:46 -05:00
J. Nick Koston aee2fc5761 [core] Extract cache helpers into esphome/compiled_config.py
storage_json.py is for the JSON sidecar; the validated-config cache
is YAML. Move it out into its own module.

Also consolidate the dispatcher's open-coded fast path (load cache +
load sidecar + apply_to_core) into a single load_compiled_config()
entry point, and collapse save_compiled_config()'s two try blocks
into one. mtime comparison gets its own _cache_is_fresh() helper so
the loader reads top to bottom.
2026-05-12 15:45:47 -05:00
J. Nick Koston 26d2d4f65d [core] Make validated-config cache automatic, no flag
Drop the `--from-storage-json` CLI flag. `esphome upload` and
`esphome logs` now always try the validated-config cache and
transparently fall back to `read_config()` when it's missing, stale
(YAML mtime > cache mtime), or corrupt. No caller change is required
to benefit, and a cold cache never produces a worse outcome than
today.

`compile` continues to write the cache unconditionally so the next
upload / logs against this YAML can skip validation; it itself
always re-validates since code generation needs the fully validated
config.
2026-05-12 15:38:57 -05:00
J. Nick Koston 6a8a1d5256 [core] Cache validated config for --from-storage-json fast path
Drop the StorageJSON `compiled_config` field and the
`esphome/lite_config.py` module from the first iteration. The earlier
shape stored the entire validated config inside the JSON sidecar, but
configs can grow past a megabyte once packages and substitutions
expand, and JSON can't round-trip the YAML-specific types (lambdas,
ID instances, includes) the validation pipeline produces.

Instead: dump the validated config to its own YAML file alongside the
sidecar (`<file>.validated.yaml`), using `yaml_util.dump` so all
esphome-specific tags survive the round trip. The fast path loads it
back with `yaml_util.load_yaml(clear_secrets=False)` -- no schema
validation, no final-validate, no external-component refresh.

Staleness is gated by mtime: if the source YAML mtime is newer than
the cache, the dispatcher falls back to a full `read_config()` with a
warning. The cache is refreshed on every successful compile via
`writer.update_storage_json`, so the dashboard's compile -> upload
-> logs flow always sees a fresh cache.

Drift surface shrinks to "what does yaml_util.dump emit" rather than
"which top-level keys does upload/logs read" -- when those subcommands
gain a new dependency, the cache already carries it.
2026-05-12 15:34:07 -05:00
J. Nick Koston eeaa8dee7b [core] Add --from-storage-json flag to upload and logs
When a downstream caller (typically a dashboard) already has a
known-good firmware binary on disk and only needs the CLI to ship
bytes to a device or stream logs back, running the full
``read_config()`` pipeline for every subcommand is dead work. For
the device-builder REMOTE install flow that runs compile, upload,
and logs back-to-back this means three "Reading configuration ..."
passes for one user action.

Add an opt-in ``--from-storage-json`` flag to ``upload`` and
``logs`` that sources platform / build metadata from the
StorageJSON sidecar produced by the last successful compile and
re-parses just enough of the YAML head (substitutions + packages,
no schema validation) to recover the ``api:`` / ``logger:`` /
``ota:`` / network blocks the subcommands consult.

The flag is opt-in and falls back to a full ``read_config()`` pass
when the sidecar is missing or older than the YAML, so a cold cache
never produces a worse outcome than today. ``compile`` / ``run`` /
``clean`` / ``bundle`` continue to validate as before.
2026-05-12 15:01:37 -05:00
J. Nick Koston 8edc9f4cc8 Merge remote-tracking branch 'upstream/dev' into integration 2026-05-12 12:52:15 -05:00
Clyde Stubbs 4ff946ac15 [cli] Add --no-states flag to run command (#16366) 2026-05-12 07:52:07 -04:00
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
J. Nick Koston 55ef66cc26 [helpers] Re-enable ProgressBar under --dashboard mode (#16357) 2026-05-11 13:12:55 -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
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
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
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
J. Nick Koston f295d6b056 Merge remote-tracking branch 'upstream/dev' into integration
# Conflicts:
#	esphome/__main__.py
#	esphome/components/api/client.py
#	esphome/components/bl0942/bl0942.cpp
#	esphome/components/cover/__init__.py
#	esphome/components/cover/automation.h
#	esphome/components/esphome/ota/ota_esphome.cpp
#	esphome/components/ota/ota_backend_esp_idf.cpp
#	esphome/components/ota/ota_partitions_esp_idf.cpp
#	esphome/espota2.py
#	tests/components/template/common-base.yaml
#	tests/unit_tests/components/api/test_client.py
#	tests/unit_tests/test_main.py
2026-05-06 16:47:31 -05:00
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
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 85f33978e7 [core] Skip external component update on esphome clean (#16268) 2026-05-06 07:23:35 -04: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
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 9ddb828da3 [api] Don't tear down log connection on stack-trace decode failure (#16196) 2026-05-03 20:05:13 -05:00
J. Nick KostonandCopilot Autofix powered by AI 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
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
J. Nick Koston 178327469e Merge branch 'partition-table-ota' into integration 2026-05-03 18:21:01 -05:00
J. Nick Koston b75f5034e5 [ota] Address remaining Copilot comments on partition-table OTA
- upload_program: allow MQTT/MQTTIP devices for --partition-table.
  MQTTIP gets resolved to a real IP by _resolve_network_devices(), so
  rejecting any non-NETWORK port_type was incorrect; only SERIAL and
  BOOTSEL are non-OTA upload paths.
- update_partition_table: re-initialize NVS on every failure path past
  nvs_flash_deinit() so components that survive a failed OTA aren't
  left with broken NVS handles. Success path stays as-is because the
  device reboots immediately afterwards.

Adds an MQTTIP upload test and refreshes the gate's comment.
2026-05-03 09:29:05 -05:00
J. Nick Koston b788529ad7 [ota] Polish partition-table review feedback
Split the combined "missing app, otadata, or nvs" verify failure into
three separate ESP_LOGE messages so users can see which check failed,
trim trailing spaces from the (err=0x%X) log strings, and document why
the partition-table espota2 test mocks SERVER_FEATURE_SUPPORTS_COMPRESSION
(intentional protocol-path coverage; the real IDFOTABackend never sets it).
2026-05-03 09:17:40 -05:00
J. Nick Koston 51c5500809 [ota] Validate partition-table binary host-side before OTA
Read the resolved partition-table file in upload_program before opening
a network connection. Reject anything that isn't 0xC00 bytes, doesn't
start with ESP_PARTITION_MAGIC, or is missing the MD5 checksum entry, so
mistakes (wrong file, swapped --file path) surface as a local error
instead of a post-handshake OTA_RESPONSE_ERROR_PARTITION_TABLE_VERIFY.

Includes unit tests covering size, magic, md5-presence, missing-file,
and end-to-end upload_program rejection, plus three real partition
tables checked in as fixtures (ESPHome build, ESP-IDF Hello-world,
esphome_dashboard prebuilt).
2026-05-03 09:15:28 -05:00
J. Nick Koston cb81ede701 Merge remote-tracking branch 'upstream/api-logs-decode-noraise' into integration 2026-05-01 12:09:10 -05:00
J. Nick Koston c05e66669e [api] Tidy decoder warning when EsphomeError has no message
_run_idedata raises EsphomeError() with no message, so the warning
shows 'unavailable ()' which looks like a bug. Use a generic fallback
explanation when str(exc) is empty.
2026-05-01 12:09:00 -05:00
J. Nick Koston 67b839c4bb Merge remote-tracking branch 'upstream/api-logs-decode-noraise' into integration 2026-05-01 12:06:19 -05:00
J. Nick Koston f4d3fb1a18 [api] Short-circuit log-line decoder after first failure
_decode_pc shells out to PlatformIO via _run_idedata; without a
populated build dir for the device that subprocess fails for every
PC/BT line in a crash dump. Disable decoding after the first
EsphomeError (per logs session) and emit a single user-facing warning
instead of retrying on every line.

Also rename the helper to _LogLineProcessor since it now owns the
per-session decode-enabled state, not just the decode call.
2026-05-01 12:01:19 -05:00
J. Nick Koston fcc6f04805 [api] Don't tear down log connection on stack-trace decode failure
When 'esphome logs' processes a crash backtrace from the device,
process_stacktrace -> _decode_pc -> _run_idedata can raise
EsphomeError if the local build dir hasn't been populated (e.g. the
device was flashed from a different machine). on_log runs inside an
asyncio protocol callback, so the unhandled exception triggers
'Fatal error: protocol.data_received() call failed.', the loop tears
the connection down, and ReconnectLogic immediately reconnects. The
device replays the same crash trace and we loop forever.

Wrap the per-line decode in a helper that swallows EsphomeError so
the connection stays up. Also covered with unit tests for the new
helper.
2026-05-01 11:56:19 -05:00
Mat931 2dd8a9913b Fix 2026-05-01 18:15:40 +02:00
pre-commit-ci-lite[bot] 2068d114eb [pre-commit.ci lite] apply automatic fixes 2026-05-01 16:02:30 +00:00
Mat931 015decce4d Merge branch 'dev' into partition-table-ota 2026-05-01 16:01:01 +00:00
Mat931andJ. Nick Koston 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