Unified firmware: runtime Bluetooth Proxy switch + Stable/Beta channel OTA#80
Unified firmware: runtime Bluetooth Proxy switch + Stable/Beta channel OTA#80bharvey88 wants to merge 1 commit into
Conversation
…-only OTA One firmware image per channel replaces the build-time _BLE split: bluetooth_proxy + esp32_ble_tracker compile into every variant and a "Bluetooth Proxy" switch (default off, persisted) starts/stops scanning at runtime. The Firmware Channel select swaps the OTA manifest URL directly - no ble_firmware selector, no manifest-matching guard, no pre-OTA BLE disable (ESPHome's OTA quiesces BLE itself). - http_request consolidated into Core.yaml with the proven buffer sizes (rx 5120 for GitHub's ~3.6KB CSP header line, tx 2048 for the ~850-char signed-redirect query) - apply_ota_source is channel-only; MSR-2_BLE.yaml keeps legacy devices on the firmware-ble manifests via substitution overrides - beta-channel/ wrappers default the select to Beta; build-beta.yml publishes manifest-standard.json + manifest-ble.json to the rolling beta-fw pre-release (absolute URLs) - build.yml now serves the end-user MSR-2.yaml image at firmware/ and moves the improv Factory image to firmware-factory/ (installer page repointed) - version 26.7.12.1 Ported from MSR-1 26.7.9.1 (ApolloAutomation/MSR-1 #100, #103, #104). Supersedes #79. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
WalkthroughAdds stable/beta OTA channel controls, beta firmware build and prerelease publishing workflows, beta-channel ESPHome wrappers, updated firmware variant mappings, and factory-manifest routing for the web installer. ChangesFirmware delivery
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant GitHubActions
participant ESPHomeBuild
participant beta_fw
participant esp_web_install_button
GitHubActions->>ESPHomeBuild: build standard and BLE beta targets
ESPHomeBuild-->>GitHubActions: return firmware artifacts
GitHubActions->>beta_fw: publish manifests and binaries
esp_web_install_button->>beta_fw: load factory manifest
Suggested reviewers: 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 |
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 775-788: Replace the fixed delay in the update_firmware on_press
sequence with synchronization on the update entity’s manifest refresh/completion
or availability state for the selected channel. Ensure
id(update_http_request).perform(true) runs only after the new channel’s
update_info and URL are populated, while preserving the existing
apply_ota_source execution and wait steps.
🪄 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: 93b9b450-d466-4819-9c02-b4555a93125e
📒 Files selected for processing (9)
.github/workflows/build-beta.yml.github/workflows/build.ymlIntegrations/ESPHome/Core.yamlIntegrations/ESPHome/MSR-2.yamlIntegrations/ESPHome/MSR-2_BLE.yamlIntegrations/ESPHome/MSR-2_Factory.yamlIntegrations/ESPHome/beta-channel/MSR-2.yamlIntegrations/ESPHome/beta-channel/MSR-2_BLE.yamlstatic/index.html
💤 Files with no reviewable changes (2)
- Integrations/ESPHome/MSR-2.yaml
- Integrations/ESPHome/MSR-2_Factory.yaml
| - platform: template | ||
| name: "Firmware Update" | ||
| id: update_firmware | ||
| icon: mdi:cloud-download | ||
| entity_category: "config" | ||
| on_press: | ||
| - logger.log: "Applying firmware update for the selected channel" | ||
| - delay: 3s | ||
| - 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 | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
ref="$(gh api repos/esphome/esphome/releases/latest --jq .tag_name)"
curl -fsSL \
"https://raw.githubusercontent.com/esphome/esphome/${ref}/esphome/components/http_request/update/http_request_update.cpp" |
sed -n '/HttpRequestUpdate::update()/,/^}/p; /HttpRequestUpdate::perform(bool force)/,/^}/p'Repository: ApolloAutomation/MSR-2
Length of output: 1061
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Inspect the relevant section in the repo config
file='Integrations/ESPHome/Core.yaml'
wc -l "$file"
sed -n '720,820p' "$file"
# Find definitions/usages related to the update request and channel selection
rg -n 'update_http_request|apply_ota_source|selected channel|manifest|update_info|perform\(true\)|component.update|script.execute: apply_ota_source' "$file"Repository: ApolloAutomation/MSR-2
Length of output: 4292
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
file='Integrations/ESPHome/Core.yaml'
# Read the OTA script and any state-dependent logic around the update entity.
sed -n '900,950p' "$file"
printf '\n---\n'
rg -n 'update_http_request|update_state|update.is_available|update_info|available|state:' "$file"
# Pull the exact ESPHome source for the update component to check async behavior and state transitions.
ref="$(gh api repos/esphome/esphome/releases/latest --jq .tag_name)"
curl -fsSL "https://raw.githubusercontent.com/esphome/esphome/${ref}/esphome/components/http_request/update/http_request_update.cpp" \
| sed -n '1,220p'Repository: ApolloAutomation/MSR-2
Length of output: 10858
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
file='Integrations/ESPHome/Core.yaml'
# Check whether the config already waits on any explicit update completion signal.
rg -n 'wait_until:|update_http_request|update\.is_available|UPDATE_STATE_AVAILABLE|publish_state|firmware update|channel' "$file"
# Inspect the ESPHome update component source for state publication and whether perform(true) ignores availability.
ref="$(gh api repos/esphome/esphome/releases/latest --jq .tag_name)"
curl -fsSL "https://raw.githubusercontent.com/esphome/esphome/${ref}/esphome/components/http_request/update/http_request_update.cpp" \
| sed -n '1,160p'Repository: ApolloAutomation/MSR-2
Length of output: 7246
Wait for the manifest refresh to finish before forcing installation. component.update is asynchronous, so the fixed 5s delay can still race and perform(true) may flash the previous update_info or an empty URL if the new channel manifest hasn’t landed yet. Hook this to the update entity’s completion/available state for the selected channel instead of a timer. Integrations/ESPHome/Core.yaml:781-788
🤖 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 775 - 788, Replace the fixed
delay in the update_firmware on_press sequence with synchronization on the
update entity’s manifest refresh/completion or availability state for the
selected channel. Ensure id(update_http_request).perform(true) runs only after
the new channel’s update_info and URL are populated, while preserving the
existing apply_ota_source execution and wait steps.
Version: 26.7.12.1
What does this implement/fix?
Ports the MSR-1 unified-firmware redesign (shipped there as 26.7.9.1 — ApolloAutomation/MSR-1#100, ApolloAutomation/MSR-1#103, ApolloAutomation/MSR-1#104) to MSR-2. One image per channel replaces the standard/_BLE build split:
bluetooth_proxy+esp32_ble_trackernow compile into every variant. A new "Bluetooth Proxy" switch (default off, persisted) starts/stops scanning at runtime;esp32_improvon the Factory image keeps working because the BLE stack stays up.apply_ota_source: a directset_source_urlswap. Noble_firmwareselector, no manifest-matching guard, and no pre-OTA BLE disable (ESPHome's OTA quiesces BLE itself).http_requestconsolidated into Core.yaml withbuffer_size_rx: 5120/buffer_size_tx: 2048— GitHub release redirects overflow the 512-byte defaults (~3.6 KB CSP header line, ~850-char signed query string).MSR-2_BLE.yamlstays for existing BLE installs; substitution overrides keep them on thefirmware-ble/manifests.beta-channel/wrappers default the select to Beta; new build-beta.yml publishesmanifest-standard.json/manifest-ble.json(absolute asset URLs) to a rollingbeta-fwpre-release. The tag is deliberately not namedbeta: a tag sharing a branch name shadows the branch forgit fetchand ESPHome remote packages.firmware/; the improv Factory image moves tofirmware-factory/;static/index.htmlrepointed to match. install.apolloautomation.com needs the same repoint when this ships to main (mirrors MSR-1 installer PR Point MSR-1 installer at the factory image (restores Wi-Fi setup step) installer#16).Flash fit: today's MSR-2_BLE image already carries web_server + bluetooth_proxy and builds green, so the unified content is known to fit on the 4MB C3; CI here re-measures all three variants.
Supersedes #79.
Types of changes
Checklist / Checklijst:
If user-visible functionality or configuration variables are added/modified:
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements