From 3f5d351ac72db6ba934d9c5184f2133652c632eb Mon Sep 17 00:00:00 2001 From: Brandon Harvey <8107750+bharvey88@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:35:02 -0500 Subject: [PATCH] Add Bluetooth Proxy firmware switching from HA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- Integrations/ESPHome/Core.yaml | 44 +++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/Integrations/ESPHome/Core.yaml b/Integrations/ESPHome/Core.yaml index f1cbbdb..8cc47bf 100644 --- a/Integrations/ESPHome/Core.yaml +++ b/Integrations/ESPHome/Core.yaml @@ -1,12 +1,13 @@ substitutions: - version: "26.7.8.4" + version: "26.7.8.5" device_description: ${name} made by Apollo Automation - version ${version}. # Default OTA password. Override in your device YAML by re-declaring # `substitutions: { ota_password: !secret _ota_password }` so each # device on your network uses a unique secret instead of the shared default. ota_password: "apolloautomation" - # Firmware variant identity: overridden to "true" by MSR-1_BLE.yaml so - # each image tracks its own OTA manifests. + # Firmware variant identity: overridden to "true" by MSR-1_BLE.yaml. Seeds + # the Bluetooth Proxy select on boot so it self-corrects to what is + # actually running after a failed or abandoned switch. ble_firmware: "false" # Default update channel on first boot (no stored user choice yet, i.e. a # fresh flash). The beta-channel builds override this to "Beta" (see @@ -18,6 +19,22 @@ substitutions: stable_manifest_base: "https://apolloautomation.github.io/MSR-1" beta_manifest_base: "https://github.com/ApolloAutomation/MSR-1/releases/download/beta-fw" +esphome: + # List form so package merging concatenates with each variant's own on_boot + # entries (mapping form would be replaced by the variant's block instead). + on_boot: + - priority: -100 + then: + # The Bluetooth Proxy select mirrors the firmware actually running, so + # a failed or abandoned switch snaps back to the truth on reboot. + - lambda: |- + if (std::string("${ble_firmware}") == "true") { + id(firmware_ble).publish_state("Enabled"); + } else { + id(firmware_ble).publish_state("Disabled"); + } + - script.execute: apply_ota_source + esp32: variant: esp32c3 flash_size: 4MB @@ -768,14 +785,29 @@ select: then: - script.execute: apply_ota_source + - platform: template + name: "Bluetooth Proxy" + id: firmware_ble + icon: mdi:bluetooth + entity_category: "config" + optimistic: true + restore_value: true + options: + - "Disabled" + - "Enabled" + initial_option: "Disabled" + on_value: + then: + - script.execute: apply_ota_source + script: - id: apply_ota_source - # Sets the OTA manifest URL from the Firmware Channel select - # (Stable/Beta) for the firmware variant this image was built as. + # Sets the OTA manifest URL from the two selectors: Bluetooth Proxy + # (Disabled/Enabled) x Firmware Channel (Stable/Beta). # Stable = GitHub Pages, Beta = rolling "beta" release assets. then: - lambda: |- - const bool ble = std::string("${ble_firmware}") == "true"; + const bool ble = id(firmware_ble).current_option() == "Enabled"; const bool beta = id(firmware_channel).current_option() == "Beta"; std::string url; if (beta) {