Skip to content

Unified firmware: runtime Bluetooth Proxy switch + Stable/Beta channel OTA#80

Open
bharvey88 wants to merge 1 commit into
betafrom
unified/firmware-channel
Open

Unified firmware: runtime Bluetooth Proxy switch + Stable/Beta channel OTA#80
bharvey88 wants to merge 1 commit into
betafrom
unified/firmware-channel

Conversation

@bharvey88

@bharvey88 bharvey88 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

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_tracker now compile into every variant. A new "Bluetooth Proxy" switch (default off, persisted) starts/stops scanning at runtime; esp32_improv on the Factory image keeps working because the BLE stack stays up.
  • New "Firmware Channel" select (Stable/Beta) + apply_ota_source: a direct set_source_url swap. No ble_firmware selector, no manifest-matching guard, and no pre-OTA BLE disable (ESPHome's OTA quiesces BLE itself).
  • http_request consolidated into Core.yaml with buffer_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.yaml stays for existing BLE installs; substitution overrides keep them on the firmware-ble/ manifests.
  • beta-channel/ wrappers default the select to Beta; new build-beta.yml publishes manifest-standard.json / manifest-ble.json (absolute asset URLs) to a rolling beta-fw pre-release. The tag is deliberately not named beta: a tag sharing a branch name shadows the branch for git fetch and ESPHome remote packages.
  • build.yml: the end-user MSR-2.yaml image now publishes to firmware/; the improv Factory image moves to firmware-factory/; static/index.html repointed 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

  • Bugfix (fixed change that fixes an issue)
  • New feature (thanks!)
  • Breaking change (repair/feature that breaks existing functionality)
  • Dependency Update - Does not publish
  • Other - Does not publish
  • Website of github readme file update - Does not publish
  • Github workflows - Does not publish

Checklist / Checklijst:

  • The code change has been tested and works locally
  • The code change has not yet been tested

If user-visible functionality or configuration variables are added/modified:

  • Added/updated documentation for the web page

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Stable/Beta firmware channel selection with automatic OTA source updates.
    • Added a manual “Firmware Update” control.
    • Added a Bluetooth Proxy switch to control BLE scanning.
    • Added beta-channel firmware builds for standard and BLE devices.
    • Added support for publishing standard, factory, and BLE firmware variants.
  • Improvements

    • Updated the web installer to load the factory firmware package.
    • Improved startup behavior so firmware channel and Bluetooth settings are restored automatically.

…-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)
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds 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.

Changes

Firmware delivery

Layer / File(s) Summary
OTA channel and device controls
Integrations/ESPHome/Core.yaml
Adds stable/beta manifest selection, a firmware update button, BLE proxy scanning control, startup reapplication, and updated HTTP request settings.
Variant and beta-channel configurations
Integrations/ESPHome/MSR-2.yaml, Integrations/ESPHome/MSR-2_BLE.yaml, Integrations/ESPHome/MSR-2_Factory.yaml, Integrations/ESPHome/beta-channel/*
Adds BLE OTA manifest substitutions, beta-channel wrappers, and removes explicit SSL or BLE runtime overrides.
Firmware build and beta release publishing
.github/workflows/build.yml, .github/workflows/build-beta.yml, static/index.html
Builds additional firmware variants, publishes rewritten beta manifests and binaries to beta-fw, and points the installer at the factory manifest.

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
Loading

Suggested reviewers: trevorschirmer

Poem

A rabbit hops through beta skies,
With fresh firmware in its files.
Stable, Beta—choose your way,
BLE scans through dawn to day.
Factory boots, releases gleam!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main user-facing changes: unified firmware, a runtime Bluetooth Proxy switch, and Stable/Beta OTA channel selection.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch unified/firmware-channel

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6d80904 and 6f359db.

📒 Files selected for processing (9)
  • .github/workflows/build-beta.yml
  • .github/workflows/build.yml
  • Integrations/ESPHome/Core.yaml
  • Integrations/ESPHome/MSR-2.yaml
  • Integrations/ESPHome/MSR-2_BLE.yaml
  • Integrations/ESPHome/MSR-2_Factory.yaml
  • Integrations/ESPHome/beta-channel/MSR-2.yaml
  • Integrations/ESPHome/beta-channel/MSR-2_BLE.yaml
  • static/index.html
💤 Files with no reviewable changes (2)
  • Integrations/ESPHome/MSR-2.yaml
  • Integrations/ESPHome/MSR-2_Factory.yaml

Comment on lines +775 to +788
- 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant