Release 26.7.9.1: merge beta into main#97
Conversation
Promote the hardcoded `password: "apolloautomation"` literal in
`MSR-1.yaml` and `MSR-1_BLE.yaml` to a `${ota_password}` substitution
defined in `Core.yaml`, defaulting to the same value. Existing consumers
see no behavior change. Consumers who include this file via `packages:`
can override per-device via their own `substitutions:` block.
Fork-submitted PRs get a read-only token on pull_request runs, so the label and assignee bots fail with 403. pull_request_target runs in the base repo context with a write token; safe here because neither job checks out or executes PR code. Build jobs stay on pull_request. Trim ci.yml permissions to what the builds need.
chore(esphome): parameterize OTA password (preserve current default)
Port the managed firmware update system from R_PRO-1 to all MSR-1 variants: - Add http_request OTA platform alongside the existing esphome OTA - Add update component pulling the firmware manifest from GitHub Pages - Add safe_mode for recovery from failed updates - Build and publish the BLE variant (firmware-ble) so BLE devices update from their own manifest instead of being converted to the factory firmware
The http_request update component polls every 6h and the first poll fires before the network is up, so a freshly booted device would not see an available update for 6 hours. Trigger a manifest check as soon as WiFi connects.
Home Assistant shows only the first 255 characters of an ESPHome release summary, so boilerplate is expensive and ## headings render oversized in the update dialog: - Render category titles and What's Changed in bold instead of H2 - Drop the star-the-repo footer - Drop the Full Changelog line: it semver-truncates 4-part versions (always links ...X.Y.Z.1) - the shared build workflow now appends a correct compare link instead
Fix label-check and auto-assign on fork PRs
Add managed firmware update system
Bump Core.yaml version to 26.6.17.1
Same Stable/Beta channel switching as CAST-1 (ApolloAutomation/CAST-1#43 naming): - Firmware Channel select (Stable/Beta) sets the OTA manifest URL via a new apply_ota_source script; each image tracks its own variant's manifests through the ble_firmware substitution. - Firmware Update button force-installs the selected channel's firmware. - build-beta.yml publishes beta builds to a rolling beta pre-release. - build.yml now builds MSR-1.yaml as firmware/ so updates serve the end-user image; the Factory image moves to firmware-factory/ for the web installer only. Version: 26.7.7.1 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add Firmware Channel switching from HA
The rolling pre-release created a tag named "beta", colliding with the beta branch. git resolves a bare fetch refspec to refs/tags/ before refs/heads/, so ESPHome remote packages pinned to ref: beta silently fetch the tag (which pointed at main's HEAD at creation and never moves) instead of the branch tip - users following beta as a package get stale YAML no matter how often they clean caches. Rename the release tag to beta-fw and update beta_manifest_base to match. The old beta release/tag should be deleted after this merges and the renamed release is populated. Version: 26.7.8.2 (26.7.8.1 is reserved by the open Bluetooth Proxy PR #90, which will need a rebase over this) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Rename rolling beta release tag to beta-fw (branch/tag collision)
A fresh flash has no stored channel preference, so the select fell back to "Stable" even on firmware obtained from the beta channel - and the update entity then offered the older stable build as a "downgrade". Make initial_option a substitution (firmware_channel_default, still "Stable") and add 8-line beta-channel/ wrapper yamls that override it to "Beta"; build-beta.yml now builds those wrappers. Stable (Pages) builds are unchanged. Same override pattern as variant wrappers. Version: 26.7.8.4 (26.7.8.3 is held by open PR #90) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Default the Firmware Channel select to Beta on beta-channel builds
Second half of the AIR-1 #107 split: lets users swap between the standard and Bluetooth-proxy images from HA instead of reflashing over USB or editing YAML. - Bluetooth Proxy select (Disabled/Enabled) joins Firmware Channel in composing the OTA manifest URL via apply_ota_source. - On boot each image publishes its real identity into the select (ble_firmware substitution), so a failed or abandoned switch snaps back to the truth. - Same-version variant switches install via the existing Firmware Update force button (merged in #89), which already frees heap by disabling BLE during the download. No workflow changes: build-beta.yml and Pages already publish both variants and their manifests. Version: 26.7.8.5 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add Bluetooth Proxy firmware switching from HA
Hardware testing surfaced two OTA bugs (thanks Brandon): - GitHub release-asset URLs answer with a redirect whose signed Location header exceeds esp_http_client's 512-byte default rx buffer, so every beta-channel manifest fetch failed with "HTTP_CLIENT: Out of buffer". Set buffer_size_rx: 2048 on all images. - update.perform(force) installs whatever manifest was last fetched successfully. Combined with the fetch failure above, pressing Firmware Update on the Beta channel silently installed the cached STABLE manifest - downgrading the device to the old image (which also wiped its saved settings, including WiFi, on boot). The button now verifies the cached manifest URL matches the selected channel and variant before performing, and refuses with a clear log line otherwise. Version: 26.7.8.6 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Fix beta manifest fetch and guard force-install against stale manifests
The redirect on release-asset downloads carries a ~3.6 KB Content-Security-Policy header line; esp_http_client requires each header line to fit the rx buffer, so 2048 still failed with "HTTP_CLIENT: Out of buffer" (confirmed on hardware running 26.7.8.6; the new manifest guard correctly refused to install, so no downgrade). Version: 26.7.8.7 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Raise http_request rx buffer to 5120 for GitHub's CSP header
IDF's esp_http_client emits "Out of buffer" from request-line composition: GET <path>?<query> must fit buffer_size_tx. GitHub's release-asset redirect points at a signed URL with a ~850-char query string, so the follow-up request could never be built in the 512-byte default TX buffer - this is why esp_http_client_open failed, and why raising the RX buffer (#93, #94) didn't help. Confirmed against the IDF source (esp_http_client.c, http_client_prepare_first_line). Version: 26.7.8.8 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Set http_request buffer_size_tx: 2048 - the real Out of buffer fix
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
Warning Review limit reached
Next review available in: 30 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
WalkthroughAdds manifest-driven OTA controls and firmware-channel selection in ESPHome configs, a beta firmware build/publish workflow, expanded firmware build outputs, workflow trigger/permission changes, release-drafter formatting updates, and a static installer manifest URL change. ChangesFirmware OTA Update Flow
CI and Release Workflow Updates
Estimated code review effort: 4 (Complex) | ~55 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bump Core.yaml version to 26.7.9.1
Resolves the autoassign.yml and ci.yml conflicts by adopting the shared ApolloAutomation/Workflows reusable workflows while keeping fork-PR support: - autoassign.yml: thin caller of the shared autoassign workflow, triggered on pull_request_target so fork PRs get assigned (fork-skip guard removed). - ci.yml: thin caller of the shared esphome-ci workflow (default stable/beta/dev matrix); label-check stays in its own pull_request_target caller (label-check.yml), since build and label-check need different triggers. Also brings in main's dependabot config and drops the duplicate root PULL_REQUEST_TEMPLATE.md. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/label-check.yml (1)
20-20: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winPin the reusable workflow ref to a commit SHA for supply-chain safety.
Using
@mainmeans any change to the upstreamApolloAutomation/Workflowsrepo is automatically picked up. If that repo is compromised, the called workflow executes with this repo'spull-requests: writeandissues: writetoken permissions. Pinning to a specific SHA ensures reproducible, auditable runs.🔒️ Suggested change
- uses: ApolloAutomation/Workflows/.github/workflows/label-check.yml@main + uses: ApolloAutomation/Workflows/.github/workflows/label-check.yml@<pinned-sha>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/label-check.yml at line 20, The reusable workflow reference in the label-check workflow is using a moving branch ref, which should be pinned for safety. Update the `uses` entry in the workflow that calls `ApolloAutomation/Workflows/.github/workflows/label-check.yml` to reference a specific commit SHA instead of `@main`, so the `label-check.yml` workflow runs against a fixed, auditable version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Integrations/ESPHome/Core.yaml`:
- Around line 687-735: The BLE re-enable logic in the Firmware Update button
flow is unconditional because the step after
id(update_http_request).perform(true) always runs; move the
esp32_ble::global_ble->enable() call into the same branch that handles the
manifest mismatch/no-update case, or track whether this action actually disabled
BLE first. Use the unique symbols on_press,
id(update_http_request).perform(true), and
esp32_ble::global_ble->disable()/enable() to keep the enable call gated only
when no firmware update was started.
---
Nitpick comments:
In @.github/workflows/label-check.yml:
- Line 20: The reusable workflow reference in the label-check workflow is using
a moving branch ref, which should be pinned for safety. Update the `uses` entry
in the workflow that calls
`ApolloAutomation/Workflows/.github/workflows/label-check.yml` to reference a
specific commit SHA instead of `@main`, so the `label-check.yml` workflow runs
against a fixed, auditable version.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b695e104-c1a9-4701-a43b-fdea7c7cfa3d
📒 Files selected for processing (13)
.github/release-drafter.yml.github/workflows/autoassign.yml.github/workflows/build-beta.yml.github/workflows/build.yml.github/workflows/ci.yml.github/workflows/label-check.ymlIntegrations/ESPHome/Core.yamlIntegrations/ESPHome/MSR-1.yamlIntegrations/ESPHome/MSR-1_BLE.yamlIntegrations/ESPHome/MSR-1_Factory.yamlIntegrations/ESPHome/beta-channel/MSR-1.yamlIntegrations/ESPHome/beta-channel/MSR-1_BLE.yamlstatic/index.html
💤 Files with no reviewable changes (1)
- .github/workflows/ci.yml
Sync main into beta; converge CI on shared reusable workflows
|
Ready for review — conflicts cleared. CI heads-up for the reviewer: the only red is |
The encryption key is set during Home Assistant adoption and saved to flash, so it persists across OTA/firmware updates. No key is committed to the repo. Non-breaking: unencrypted clients keep working until a key is set. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add API encryption (no pre-configured key)
…-only OTA Replaces the build-time BLE variant machinery with runtime toggles: - Compile bluetooth_proxy + esp32_ble_tracker into Core.yaml so every variant inherits it (base ~94.1% flash, Factory ~95.4% - both fit 4MB). - Add a "Bluetooth Proxy" switch (default off) that starts/stops scanning via esp32_ble_tracker; the esp32_ble stack stays up so esp32_improv keeps working on the Factory image. - Remove the firmware_ble manifest selector. apply_ota_source is now channel-only, using per-variant manifest bases (ota_stable_manifest / ota_beta_manifest) so legacy MSR-1_BLE devices keep their firmware-ble manifest. - Delete the manifest-matching guard and simplify the Firmware Update flow: drop the BLE stack for the TLS download, restore it + the switch's scan state on the not-started path, and let the post-update reboot restore the switch. This also fixes the unconditional BLE re-enable CodeRabbit flagged. - MSR-1_BLE.yaml: drop its now-inherited bluetooth_proxy; add the manifest subs. Part of the single 26.7.9.1 release; no version bump. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Unify BLE into one firmware: runtime Bluetooth Proxy switch + channel-only OTA
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Integrations/ESPHome/Core.yaml`:
- Around line 721-726: The OTA path in apply_ota_source is still forcing
update_http_request.perform(true) after a fixed delay, which can race the async
manifest refresh. Update the flow so the install waits for the manifest refresh
to finish before continuing, or add a bounded retry/state check around
update_http_request and the script.execute/script.wait sequence to verify fresh
manifest data is present before starting OTA.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: baf96605-aadd-4305-b15a-a122ce40481d
📒 Files selected for processing (4)
.github/workflows/autoassign.yml.github/workflows/ci.ymlIntegrations/ESPHome/Core.yamlIntegrations/ESPHome/MSR-1_BLE.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
- .github/workflows/ci.yml
- Integrations/ESPHome/MSR-1_BLE.yaml
| - script.execute: apply_ota_source | ||
| - script.wait: apply_ota_source | ||
| # The manifest fetch runs in its own task; give it a fixed window to land | ||
| # (update.is_available stays false for same-version switches). | ||
| - delay: 5s | ||
| - lambda: id(update_http_request).perform(true); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Avoid racing the manifest refresh before starting OTA.
This flow schedules the manifest refresh, waits a fixed 5s, then forces perform(true). Since the comment says the fetch runs in another task, slow TLS/GitHub responses can leave this using stale or missing manifest data after a channel switch. Gate the install on refresh completion, or add a bounded retry/state check before forcing the update.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Integrations/ESPHome/Core.yaml` around lines 721 - 726, The OTA path in
apply_ota_source is still forcing update_http_request.perform(true) after a
fixed delay, which can race the async manifest refresh. Update the flow so the
install waits for the manifest refresh to finish before continuing, or add a
bounded retry/state check around update_http_request and the
script.execute/script.wait sequence to verify fresh manifest data is present
before starting OTA.
The ble_firmware substitution is no longer read by anything after the runtime Bluetooth Proxy switch replaced the firmware_ble manifest selector (#100) - remove it from Core.yaml and MSR-1_BLE.yaml. Also correct the copy-pasted device-name input in build.yml (msr-2 -> msr-1); it is a required-but-unused input in the shared workflow, so this is a no-op correctness fix. No compiled-output change; does not publish. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The http_request component config (verify_ssl + the OTA-download buffer sizes buffer_size_rx/tx) was duplicated identically across MSR-1.yaml, MSR-1_BLE.yaml, and MSR-1_Factory.yaml. Move it to Core.yaml so there is one source of truth; the ota/update http_request PLATFORMS stay in the variants and use the shared component. No compiled-output change; does not publish. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Verified on hardware that the unified build (~21% RAM at rest, ~260 KB free) completes the TLS firmware download with the Bluetooth proxy still active, so freeing RAM by dropping the BLE stack before the update is unnecessary. Remove the disable-before / re-enable-and-restore-scan-after logic; the Bluetooth proxy now stays up through the update. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…irmware Cleanup: remove vestigial ble_firmware sub; fix build.yml device-name
Consolidate http_request block into Core.yaml
Remove unneeded pre-OTA BLE disable from Firmware Update
The bluetooth_proxy component now enables active connections by default, and Home Assistant manages active-vs-passive dynamically - it opens an active connection only when an integration needs one, staying passive otherwise. So the explicit active: true is redundant with the current default. Dropping it leaves the bare bluetooth_proxy: line with identical behavior/compiled output. Ref: https://esphome.io/components/bluetooth_proxy/ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…active Drop redundant bluetooth_proxy active: true (now the default)
Version: 26.7.9.1
What does this implement/fix?
Promotes the beta channel to main. Highlights since the last release:
Types of changes
Checklist / Checklijst:
If user-visible functionality or configuration variables are added/modified:
🤖 Generated with Claude Code
Summary by CodeRabbit