Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
815df1b
Merge pull request #42 from ApolloAutomation/main
TrevorSchirmer Jul 7, 2026
a5ee01e
Rename Firmware Channel option "Main" to "Stable"
bharvey88 Jul 7, 2026
98d14a8
Merge pull request #43 from bharvey88/stable-channel-name
bharvey88 Jul 7, 2026
acc01f9
Improvement!
TrevorSchirmer Jul 8, 2026
57e2f40
Rename rolling beta release tag to beta-fw (branch/tag collision)
bharvey88 Jul 8, 2026
18c1061
Merge pull request #45 from ApolloAutomation/fix-beta-tag-collision
bharvey88 Jul 8, 2026
6e14e4b
Remove Empty Index
TrevorSchirmer Jul 8, 2026
86cf252
Merge pull request #47 from ApolloAutomation/Buffering
TrevorSchirmer Jul 8, 2026
8a5ed17
Fix ESPHome beta build: replace deprecated Select .state in wizmote.yaml
bharvey88 Jul 12, 2026
c3610d1
Merge pull request #49 from ApolloAutomation/fix/wizmote-select-state
bharvey88 Jul 12, 2026
c881f6e
Unified firmware: runtime Bluetooth Proxy switch + channel fix set
bharvey88 Jul 8, 2026
b5ad23c
Auto-assign on fork PRs via pull_request_target
bharvey88 Jul 14, 2026
3e805d0
Merge pull request #48 from ApolloAutomation/unified/firmware-channel
bharvey88 Jul 14, 2026
4762ea1
Enable API encryption
bharvey88 Jul 14, 2026
c1e24f7
Remove duplicate label-check job from CI workflow
bharvey88 Jul 14, 2026
0b39a6e
Merge pull request #53 from bharvey88/fix/ci-drop-label-check
bharvey88 Jul 14, 2026
f3d8a3c
Merge branch 'beta' into fix/api-encryption
bharvey88 Jul 14, 2026
bcd11b0
Merge branch 'beta' into fix/autoassign-fork-prs
bharvey88 Jul 14, 2026
9054301
Merge pull request #52 from bharvey88/fix/api-encryption
bharvey88 Jul 14, 2026
c2e4eed
Merge pull request #50 from ApolloAutomation/fix/autoassign-fork-prs
bharvey88 Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/autoassign.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
name: Auto Assign

# pull_request_target (not pull_request) so auto-assign works on
# fork-submitted PRs; fork pull_request runs only get a read-only token.
# Safe because this workflow never checks out or executes PR code.
on:
issues:
types: [opened]
pull_request:
pull_request_target:
types: [opened]

permissions:
Expand All @@ -12,8 +15,6 @@ permissions:

jobs:
auto-assign:
# Skip auto-assign for pull requests from forks due to GITHUB_TOKEN permission restrictions
if: github.event_name == 'issues' || github.event.pull_request.head.repo.full_name == github.repository
uses: ApolloAutomation/Workflows/.github/workflows/autoassign.yml@main
with:
assignees: bharvey88
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/build-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ jobs:
strategy:
matrix:
include:
- { yaml: Integrations/ESPHome/CAST-1_W.yaml, name: firmware-w }
- { yaml: Integrations/ESPHome/CAST-1_ETH.yaml, name: firmware-e }
- { yaml: Integrations/ESPHome/beta-channel/CAST-1_W.yaml, name: firmware-w }
- { yaml: Integrations/ESPHome/beta-channel/CAST-1_ETH.yaml, name: firmware-e }
uses: esphome/workflows/.github/workflows/build.yml@025a1e6255610c498ed590403b7e510b69e474df # 2026.4.1
with:
files: ${{ matrix.yaml }}
Expand All @@ -59,20 +59,20 @@ jobs:
path: fw
pattern: firmware*

- name: Ensure rolling 'beta' pre-release exists
- name: Ensure rolling 'beta-fw' pre-release exists
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release view beta -R "${{ github.repository }}" >/dev/null 2>&1 \
|| gh release create beta -R "${{ github.repository }}" \
gh release view beta-fw -R "${{ github.repository }}" >/dev/null 2>&1 \
|| gh release create beta-fw -R "${{ github.repository }}" \
--prerelease --title "Beta (rolling)" \
--notes "Latest CAST-1 beta firmware. Auto-updated on every push to the beta branch."

- name: Rewrite manifests to absolute URLs and upload assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BASE="https://github.com/${{ github.repository }}/releases/download/beta"
BASE="https://github.com/${{ github.repository }}/releases/download/beta-fw"
for v in w e; do
man=$(find "fw/firmware-$v" -name manifest.json | head -1)
if [ -z "$man" ]; then
Expand All @@ -87,8 +87,8 @@ jobs:
| .builds[0].parts |= map(.path = ($base + "/" + (.path | sub(".*/"; ""))))
' "$man" > "manifest-$v.json"
cat "manifest-$v.json"
gh release upload beta "manifest-$v.json" -R "${{ github.repository }}" --clobber
gh release upload beta-fw "manifest-$v.json" -R "${{ github.repository }}" --clobber
find "fw/firmware-$v" -name '*.bin' -print -exec \
gh release upload beta {} -R "${{ github.repository }}" --clobber \;
gh release upload beta-fw {} -R "${{ github.repository }}" --clobber \;
done
echo "Beta assets published."
8 changes: 0 additions & 8 deletions Integrations/ESPHome/CAST-1_ETH.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ ota:
- platform: http_request
id: ota_managed

http_request:
verify_ssl: true
# Beta OTA manifests/binaries are GitHub release assets, which 302-redirect to
# long signed CDN URLs (~900+ bytes). The default 512-byte RX buffer overflows
# ("Out of buffer"), so enlarge it. See esphome/esphome#13786.
buffer_size_rx: 4096
buffer_size_tx: 1024

safe_mode:

update:
Expand Down
8 changes: 0 additions & 8 deletions Integrations/ESPHome/CAST-1_W.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ ota:
- platform: http_request
id: ota_managed

http_request:
verify_ssl: true
# Beta OTA manifests/binaries are GitHub release assets, which 302-redirect to
# long signed CDN URLs (~900+ bytes). The default 512-byte RX buffer overflows
# ("Out of buffer"), so enlarge it. See esphome/esphome#13786.
buffer_size_rx: 4096
buffer_size_tx: 1024

safe_mode:

improv_serial:
Expand Down
126 changes: 109 additions & 17 deletions Integrations/ESPHome/Core.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
substitutions:
version: "26.7.7.1"
version: "26.7.14.1"
# 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
# Integrations/ESPHome/beta-channel/) so firmware obtained from the beta
# channel keeps tracking it instead of offering a stable "downgrade".
firmware_channel_default: "Stable"
# Manifest URL bases. Stable = GitHub Pages (main branch builds).
# Beta = rolling "beta-fw" pre-release assets (beta branch builds).
stable_manifest_base: "https://apolloautomation.github.io/CAST-1"
beta_manifest_base: "https://github.com/ApolloAutomation/CAST-1/releases/download/beta-fw"


packages:
wizmote: !include wizmote.yaml

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:
# Point the update entity at the selected type/channel manifest.
- priority: -100
then:
- script.execute: apply_ota_source
# Re-apply the Bluetooth Proxy switch after all components set up, so BLE
# scanning matches the persisted switch (proxy stays off by default).
- priority: -300
then:
- if:
condition:
switch.is_on: bluetooth_proxy_switch
then:
- esp32_ble_tracker.start_scan:
continuous: true
else:
- esp32_ble_tracker.stop_scan:

esp32:
variant: ESP32S3
flash_size: 8MB
Expand All @@ -26,7 +56,17 @@ esp32:
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y"
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y"

# BT allocations go to PSRAM first (CONFIG_BT_* options above), keeping
# internal RAM free for the audio pipelines.
esp32_ble_tracker:
id: ble_tracker
scan_parameters:
continuous: true

bluetooth_proxy:

api:
encryption:

globals:
- id: cycleCounter
Expand Down Expand Up @@ -55,11 +95,29 @@ globals:
psram:
mode: octal
speed: 80MHz
# All CAST-1 PCBs have PSRAM, so guarantee it (fail boot if absent). This flips
# ESPHome's psram_guaranteed flag, which unlocks the high-performance network
# tier: 512 WiFi RX buffers / 32 TX buffers and a much larger TCP receive
# window instead of the conservative defaults. Music Assistant bulk-downloads
# each track faster than realtime, and the small TCP window is what its flow
# control slams into at track changes/seeks. (VPE sets this too.)
ignore_not_found: false

web_server:
port: 80
version: 3

http_request:
verify_ssl: true
# GitHub release-asset downloads answer with a redirect carrying a
# ~3.6 KB Content-Security-Policy header; each header line must fit
# this buffer or the request fails with "HTTP_CLIENT: Out of buffer".
buffer_size_rx: 5120
# The redirect target is a signed URL with a ~850-char query string; the
# follow-up request line must fit the TX buffer or esp_http_client_open
# fails with "Out of buffer" before sending anything.
buffer_size_tx: 2048

i2c:
sda: GPIO47
scl: GPIO48
Expand All @@ -72,11 +130,17 @@ button:
- platform: template
name: "Firmware Update"
id: update_firmware
icon: mdi:cloud-download
entity_category: config
on_press:
then:
- lambda: |-
id(update_http_request).perform(true);
- logger.log: "Applying firmware update for the selected type and 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);

binary_sensor:
- platform: status
Expand Down Expand Up @@ -132,6 +196,19 @@ switch:
id: enable_dac
restore_mode: ALWAYS_ON

- platform: template
name: "Bluetooth Proxy"
id: bluetooth_proxy_switch
icon: mdi:bluetooth
entity_category: "config"
restore_mode: RESTORE_DEFAULT_OFF
optimistic: true
on_turn_on:
- esp32_ble_tracker.start_scan:
continuous: true
on_turn_off:
- esp32_ble_tracker.stop_scan:

text_sensor:
- platform: sendspin
type: title
Expand Down Expand Up @@ -201,9 +278,9 @@ select:
optimistic: true
restore_value: true
options:
- "Main"
- "Stable"
- "Beta"
initial_option: "Main"
initial_option: "${firmware_channel_default}"
on_value:
then:
- script.execute: apply_ota_source
Expand Down Expand Up @@ -243,30 +320,43 @@ speaker:
- id: media_mixer_input
timeout: never

# Resampler task stacks stay in internal RAM (default): they are hot audio
# tasks, and a PSRAM stack contends with the decode/ring buffers already in
# PSRAM during Music Assistant's bulk track transfers. (Matches VPE.)
- platform: resampler
id: announcement_resampling_speaker
output_speaker: announcement_mixer_input
sample_rate: 48000
bits_per_sample: 16

- platform: resampler
id: media_resampling_speaker
output_speaker: media_mixer_input
task_stack_in_psram: true
sample_rate: 48000
bits_per_sample: 16


sendspin:
id: sendspin_hub
task_stack_in_psram: true
# Keep the sendspin server task's stack in internal RAM (VPE does the same).
# That single task services the websocket: audio ingest, JSON, and the
# time-sync replies the clock filter depends on — slowing it down with a
# PSRAM stack skews time sync, which surfaces as hard-sync silence gaps at
# track changes.
task_stack_in_psram: false

media_source:
- platform: sendspin
id: sendspin_source
decode_memory: internal
# decode_memory deliberately unset (component default, matches VPE)

- platform: audio_http
id: http_media_source
buffer_size: 200000
buffer_size: 500000

- platform: audio_http
id: http_announcement_source
buffer_size: 200000
buffer_size: 250000

media_player:
- platform: sendspin
Expand All @@ -282,7 +372,7 @@ media_player:
format: FLAC # FLAC is the least processor intensive codec
num_channels: 1 # Stereo audio is unnecessary for announcements
sample_rate: 48000
speaker: announcement_mixer_input
speaker: announcement_resampling_speaker
sources:
- http_announcement_source

Expand Down Expand Up @@ -356,21 +446,23 @@ media_player:
script:
- id: apply_ota_source
# Sets the OTA source URL from the two selectors: Firmware Type (WiFi/Ethernet)
# x Firmware Channel (Main/Beta). Main = GitHub Pages, Beta = GitHub release assets.
# x Firmware Channel (Stable/Beta). Stable = GitHub Pages (main branch builds),
# Beta = rolling "beta-fw" release assets.
then:
- lambda: |-
const bool eth = id(firmware_selector).current_option() == "Ethernet";
const bool beta = id(firmware_channel).current_option() == "Beta";
std::string url;
if (beta) {
url = eth
? "https://github.com/ApolloAutomation/CAST-1/releases/download/beta/manifest-e.json"
: "https://github.com/ApolloAutomation/CAST-1/releases/download/beta/manifest-w.json";
? "${beta_manifest_base}/manifest-e.json"
: "${beta_manifest_base}/manifest-w.json";
} else {
url = eth
? "https://apolloautomation.github.io/CAST-1/firmware-e/manifest.json"
: "https://apolloautomation.github.io/CAST-1/firmware-w/manifest.json";
? "${stable_manifest_base}/firmware-e/manifest.json"
: "${stable_manifest_base}/firmware-w/manifest.json";
}
ESP_LOGI("firmware", "OTA manifest set to: %s", url.c_str());
id(update_http_request).set_source_url(url);
- component.update: update_http_request
- id: statusCheck
Expand Down
9 changes: 9 additions & 0 deletions Integrations/ESPHome/beta-channel/CAST-1_ETH.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Beta-channel build of CAST-1_ETH.yaml: the identical image except the Firmware
# Channel select defaults to "Beta" on first boot, so firmware obtained from
# the beta channel keeps tracking it. Built by build-beta.yml only; the
# stable (GitHub Pages) builds use CAST-1_ETH.yaml directly.
substitutions:
firmware_channel_default: "Beta"

packages:
base: !include ../CAST-1_ETH.yaml
9 changes: 9 additions & 0 deletions Integrations/ESPHome/beta-channel/CAST-1_W.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Beta-channel build of CAST-1_W.yaml: the identical image except the Firmware
# Channel select defaults to "Beta" on first boot, so firmware obtained from
# the beta channel keeps tracking it. Built by build-beta.yml only; the
# stable (GitHub Pages) builds use CAST-1_W.yaml directly.
substitutions:
firmware_channel_default: "Beta"

packages:
base: !include ../CAST-1_W.yaml
Loading