Commit Graph
28591 Commits
Author SHA1 Message Date
J. Nick Koston 178327469e Merge branch 'partition-table-ota' into integration 2026-05-03 18:21:01 -05:00
J. Nick Koston 0cd682f29e Merge remote-tracking branch 'upstream/fix-valve-action-trigger-args' into integration 2026-05-03 18:20:42 -05:00
J. Nick Koston 39a47b7d47 Merge remote-tracking branch 'upstream/fix-light-action-trigger-args' into integration 2026-05-03 18:20:38 -05:00
J. Nick Koston 5c015ede77 Merge remote-tracking branch 'upstream/fix-flaky-host-mode-climate-basic-state' into integration 2026-05-03 18:20:34 -05:00
J. Nick Koston b5866f072c Merge remote-tracking branch 'upstream/fix-fan-action-trigger-args' into integration 2026-05-03 18:20:30 -05:00
J. Nick Koston 76d4f70d70 Merge remote-tracking branch 'upstream/fix-climate-action-trigger-args' into integration 2026-05-03 18:20:26 -05:00
J. Nick Koston 9f58b66f97 Merge remote-tracking branch 'upstream/dev' into integration 2026-05-03 18:20:20 -05:00
J. Nick Koston da06bb9c7f [ota] Skip safe_shutdown after partition-table OTA
For OTA_TYPE_UPDATE_PARTITION_TABLE the success path runs
nvs_flash_deinit() before the final write, which leaves every
preference handle held by other components invalid. App.safe_reboot()
calls on_safe_shutdown() which tries to flush preferences, and each
flush fails with ESP_ERR_NVS_INVALID_HANDLE -- noisy log spam during
the reboot window.

App.reboot() skips the safe-shutdown callbacks and goes straight to
esp_restart(). For partition-table OTAs there is nothing useful to
flush (NVS handles are already dead, the device is moments from a
reboot anyway), so reboot directly.

App-OTA path is unchanged: safe_reboot() still runs on_safe_shutdown
so preferences are saved on the way out.
2026-05-03 18:19:24 -05:00
J. Nick Koston aec754f9a2 Merge branch 'dev' into fix-climate-action-trigger-args 2026-05-03 17:57:53 -05: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
J. Nick Koston 59de35a7b8 [fan] Cover fan.turn_on inside on_preset_set (StringRef Ts) in tests 2026-05-03 17:52:58 -05:00
J. Nick Koston 1f9afebbf5 [ota] Make partition-table verify errors actionable
When the running app does not fit any slot in the new partition table,
the user has almost certainly picked the wrong migration .bin for
their device. Replace the generic "No compatible app partition found"
error with one that prints the running app's offset, used size, and
the size limit a migration method must clear, plus an explicit
reassurance that no flash content has been modified yet.

Same treatment for the otadata-overlap case: include the running app
offset/size and tell the user to pick a different migration method.

Verification phase is non-destructive, so these errors are recoverable
by retrying with the correct .bin -- the new wording makes that
explicit so users don't lose time on a brick scare they aren't in.

No code-flow change; only log message wording.
2026-05-03 17:52:55 -05:00
J. Nick Koston 37a44a8a6f [tests] Fix flaky host_mode_climate_basic_state by ignoring prior MEMORY state
The fixture shares the `host-climate-test` build dir with
host_mode_climate_control.yaml. When the control test runs first and
leaves the thermostat in HEAT mode, MEMORY restore on the next basic_state
boot picked up HEAT and the initial-state assertion failed
(`assert ClimateMode.HEAT == ClimateMode.OFF`).
2026-05-03 17:39:39 -05:00
J. Nick Koston 7c667bb9f4 [valve] Normalize trigger args to const remove_cvref_t<T> & 2026-05-03 17:31:09 -05:00
J. Nick Koston e4de502bd4 [fan] Normalize trigger args to const remove_cvref_t<T> & 2026-05-03 17:30:01 -05:00
J. Nick Koston 10ea8c3492 [light] Normalize trigger args to const remove_cvref_t<T> & 2026-05-03 17:29:25 -05:00
J. Nick Koston 102618b11c [climate] Normalize trigger args to const remove_cvref_t<T> & 2026-05-03 17:28:38 -05:00
J. Nick Koston 22252ef5b5 [light] Forward trigger args as Ts... so inner-lambda calls type-check 2026-05-03 17:26:39 -05:00
J. Nick Koston b62d88a5d1 [valve] Forward trigger args as Ts... so inner-lambda calls type-check 2026-05-03 17:25:30 -05:00
J. Nick Koston 431385ebc1 [valve] Use const remove_reference_t<T> & to avoid copies of non-ref Ts 2026-05-03 16:56:14 -05:00
J. Nick Koston 1509db2a2c [fan] Use const remove_reference_t<T> & to avoid copies of non-ref Ts 2026-05-03 16:55:09 -05:00
J. Nick Koston 5483b27bbf [light] Use const remove_reference_t<T> & to avoid copies of non-ref Ts 2026-05-03 16:54:21 -05:00
J. Nick Koston a73a9516c2 [climate] Use const remove_reference_t<T> & to avoid copies of non-ref Ts 2026-05-03 16:53:10 -05:00
J. Nick Koston dd0cff5f45 [light] Reword apply-fn comments to describe codegen failure mode 2026-05-03 16:51:27 -05:00
J. Nick Koston fb6920a5b1 [valve] Fix ControlAction trigger args with reference types
`const Ts &...` is ill-formed when Ts is already a reference (e.g. a
trigger that passes `std::string &`). Forward Ts by-value so the
generated lambda matches ApplyFn for any valid trigger arg type.
2026-05-03 16:12:08 -05:00
J. Nick Koston d481d0cb4a [fan] Fix TurnOnAction trigger args with reference types
`const Ts &...` is ill-formed when Ts is already a reference (e.g. a
trigger that passes `std::string &`). Forward Ts by-value so the
generated lambda matches ApplyFn for any valid trigger arg type.
2026-05-03 16:10:03 -05:00
J. Nick Koston 31239ac950 [climate] Fix ControlAction trigger args with reference types
`const Ts &...` is ill-formed when Ts is already a reference (e.g. a
trigger that passes `std::string &`). Forward Ts by-value so the
generated lambda matches ApplyFn for any valid trigger arg type.
2026-05-03 16:08:39 -05:00
J. Nick Koston 7aa9f0d796 [light] Fix LightControlAction trigger args with reference types
`const Ts &...` is ill-formed when Ts is already a reference (e.g. a
trigger that passes `std::string &`). Forward Ts by-value so the
generated lambda matches ApplyFn for any valid trigger arg type.
2026-05-03 16:06:54 -05:00
J. Nick Koston d30f82784c [ota] Drop ineffective NvsReinitGuard; soften brick wording
Mat931 verified empirically that ``nvs_flash_init()`` after
``nvs_flash_deinit()`` does not revive NVS handles already held by
other components: writes still fail with ESP_ERR_NVS_INVALID_HANDLE.
The guard therefore only created the appearance of a recovery path.

Remove it and document the actual contract: from nvs_flash_deinit()
onward, components that hold open NVS handles will fail until the
device is rebooted. The success path reboots immediately, so it is
unaffected; the failure path now tells the user clearly to reboot
and retry, rather than implying retry-without-reboot will work.

Also soften the "permanently brick" wording in the pre-write log
warning -- a bad partition-table OTA leaves a device that needs a
serial flash to recover, not a permanently-dead one.
2026-05-03 14:24:59 -05:00
Mat931 c19d06a07f Format partition table similar to debug component 2026-05-03 20:47:49 +02:00
Mat931 1895ef1c3e Restore 'Used size' of running app in dump_config 2026-05-03 20:03:38 +02:00
J. Nick Koston 9a73ffbae9 Merge branch 'dev' into partition-table-ota 2026-05-03 09:49:29 -05:00
J. Nick Koston 87f152965d [ota] Rename copy_source_part -> copy_dest_part and harden running-app lookup
The PartitionTablePlan field that drives the optional app copy stores
the partition that will receive the running app (i.e. the destination
in the current table at the new slot's flash offset). The old name
``copy_source_part`` described the value backwards and risked future
callers swapping the esp_partition_copy() arguments; renamed to
``copy_dest_part`` along with the matching local
``app_copy_dest_part`` and the comments around them.

Also replace esp_ota_get_running_partition() in the copy path with
find_app_partition_at(running_app_offset, running_app_size). The IDF
call can return nullptr after a prior aborted partition-table OTA in
the same boot called esp_partition_unload_all() (the same condition
the cache in get_running_app_position() exists for); the previous code
would have dereferenced nullptr on the retry that the client error
message explicitly suggests.

No functional change on the success path; nullptr deref on the failed-
retry path is now reported as OTA_RESPONSE_ERROR_PARTITION_TABLE_UPDATE.
2026-05-03 09:48:06 -05:00
J. Nick Koston c69b3c5590 [ota] Unify backend begin() signature and trim partition-table comments
Every OTA backend's begin() now takes ``(size_t image_size, OTAType
ota_type = OTA_TYPE_UPDATE_APP)``. ESPHomeOTAComponent::handle_data_()
calls ``backend_->begin(ota_size, ota_type)`` unconditionally; the
USE_OTA_PARTITIONS ifdef around the call disappears. The four non-ESP32
backends (esp8266, rp2040, libretiny, host) accept the new parameter
and reject anything other than OTA_TYPE_UPDATE_APP up front, so the
client-visible behaviour is unchanged.

Same commit also trims the verbose block comments in the partition-
table TU and the IDF backend header, keeping the genuinely non-obvious
WHYs (slot-selection policy, NvsReinitGuard semantics, unload-then-null
ordering, cache-init flag, dump_config nullptr fallback) and dropping
the procedural narration.

No functional change.
2026-05-03 09:43:55 -05:00
J. Nick Koston d5cc5206dd [ota] Move partition-table code into ota_partitions_esp_idf.cpp
Splits the partition-table OTA implementation out of the shared
ota_backend_esp_idf.cpp into a new translation unit gated by
USE_OTA_PARTITIONS. Builds without allow_partition_access compile
strictly less code and don't link esp_image_format / nvs_flash; the
common app-OTA backend is also easier to read without ~340 lines of
unrelated partition handling interleaved.

What moves: validate_new_partition_table_, update_partition_table,
get_running_app_position, the file-static running-app cache, the
NvsReinitGuard RAII helper, and the find_app_partition_at /
check_overlap helpers. What stays: begin/write/end/abort and the
factory.

Behaviour-preserving refactor.
2026-05-03 09:34:46 -05:00
J. Nick Koston 4dcccf2cdf [ota] DRY NVS reinit on update_partition_table failure paths
Replace the four explicit nvs_flash_init() calls with a small RAII
guard (NvsReinitGuard) declared right after nvs_flash_deinit(). Each
failure path now just returns; the guard reinits NVS in its destructor.
The success path disarms it before the trailing return because the
device reboots immediately afterwards and reinit would only churn the
partition cache.

No behaviour change.
2026-05-03 09:30:23 -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 36c120fb07 [ota] Hoist running-app cache to file scope
The running-app position cache lived as three function-local statics
inside get_running_app_position(). They cannot be IDFOTABackend members
(the backend is per-connection, the cache must outlive a backend that
called esp_partition_unload_all() in a prior aborted partition-table
OTA), but burying them inside the function made the lifetime and
shared-across-connections semantics implicit. Move them to file scope
with s_running_app_ prefix so the process-scoped lifetime is visible
at first read, and tighten the surrounding comments.

No behaviour change.
2026-05-03 09:26:03 -05:00
J. Nick Koston 4490bbf23a [ota] Extract partition-table validation into validate_new_partition_table_
Splits the non-destructive validation phase out of update_partition_table()
into a dedicated method. update_partition_table() now reads top-down as
"check buffer state, find running app, validate the new table + plan the
target slot, then commit", with the destructive write isolated to the
final block.

The chosen slot and optional copy-source partition are returned via a
small PartitionTablePlan struct so the caller no longer juggles the two
candidate-index variables. Refactor only; behaviour and error semantics
are unchanged.
2026-05-03 09:23:08 -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
Edward Firmoandpre-commit-ci-lite[bot] 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
J. Nick Koston b30d09b43b Merge remote-tracking branch 'upstream/dev' into integration 2026-05-01 21:53:04 -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
Mat931 e7ee0c0b83 Merge branch 'dev' into partition-table-ota 2026-05-01 19:54:05 +00: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
J. Nick Koston 4f8aa24f05 Merge remote-tracking branch 'upstream/esp8266-wdt-feed-100ms' into integration 2026-05-01 12:48:04 -05:00
Mat931 63c9b63fcf Apply suggestions 2026-05-01 19:42:39 +02:00
J. Nick Koston cf01be6250 [esp8266] Lower WDT_FEED_INTERVAL_MS to 100 ms
Restore tighter feed cadence on ESP8266 to match the smaller WDT
budgets on this platform. ESP8266 soft WDT is ~1.6 s and HW WDT is
~6 s; a single long iteration (mDNS reply, wifi scan, OTA verify,
lwIP TCP retransmit) can easily push the loop past a few hundred ms.
The 300 ms shared default left only ~1.3 s of soft-WDT headroom; 100 ms
restores ~16x margin to the soft WDT (matching pre-#15846 behavior in
spirit) without per-iteration arch_feed_wdt() cost.

Reports of Hardware WDT - Level1Int crashes on ESP8266 line up with
this margin being too tight under the new main-loop cadence.
2026-05-01 12:25:37 -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