Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
106 changes: 106 additions & 0 deletions .github/workflows/build-beta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Build and Publish Beta

# Builds TEMP-1 firmware from the beta branch and publishes it as assets on a
# rolling "beta-fw" pre-release. The on-device "Firmware Channel" select points
# OTA updates at these assets. Stable firmware is built/published separately
# by build.yml (push to main -> GitHub Pages).

on:
push:
branches: [beta]
paths:
- 'Integrations/ESPHome/**'
workflow_dispatch:

# Least privilege: read-only by default; only publish-beta is elevated to write.
permissions:
contents: read

jobs:
version:
name: Read version
runs-on: ubuntu-latest
outputs:
v: ${{ steps.read.outputs.v }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- id: read
run: |
v=$(awk '/substitutions:/ {f=1} f && /version:/ {print $2; exit}' \
Integrations/ESPHome/Core.yaml | tr -d '"')
echo "v=$v" >> "$GITHUB_OUTPUT"
echo "Beta version: $v"

build:
name: Build ${{ matrix.name }}
needs: version
strategy:
matrix:
include:
# Beta serves OTA updates only, so it builds the end-user Minimal
# images, not the first-flash improv images. Artifact names match
# the on-device variant_slug: "", "-b", "2", "-b2".
- { yaml: Integrations/ESPHome/beta-channel/TEMP-1_Minimal.yaml, name: firmware-beta }
- { yaml: Integrations/ESPHome/beta-channel/TEMP-1B_Minimal.yaml, name: firmware-b-beta }
- { yaml: Integrations/ESPHome/beta-channel/TEMP-1_Minimal_R2.yaml, name: firmware2-beta }
- { yaml: Integrations/ESPHome/beta-channel/TEMP-1B_Minimal_R2.yaml, name: firmware-b2-beta }
uses: esphome/workflows/.github/workflows/build.yml@025a1e6255610c498ed590403b7e510b69e474df # 2026.4.1
with:
files: ${{ matrix.yaml }}
esphome-version: stable
combined-name: ${{ matrix.name }}
release-version: ${{ needs.version.outputs.v }}

publish-beta:
name: Publish beta release assets
needs: [version, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download firmware artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: fw
pattern: firmware*

- name: Ensure rolling 'beta-fw' pre-release exists
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
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 TEMP-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-fw"
# Manifest names match the on-device variant_slug: "", "-b", "2", "-b2".
declare -A DIRS=( [""]=firmware-beta ["-b"]=firmware-b-beta ["2"]=firmware2-beta ["-b2"]=firmware-b2-beta )
for v in "" "-b" "2" "-b2"; do
src="fw/${DIRS[$v]}"
man=$(find "$src" -name manifest.json | head -1)
if [ -z "$man" ]; then
echo "::error::manifest.json not found for ${DIRS[$v]}"
exit 1
fi
echo "Rewriting $man"
# Make ota.path and parts[].path absolute release-asset URLs so the
# device never has to resolve a relative path against a redirect.
# The four variants have distinct device names, so bin filenames
# don't collide in the flat release-asset namespace.
jq --arg base "$BASE" '
.builds[0].ota.path = ($base + "/" + (.builds[0].ota.path | sub(".*/"; "")))
| .builds[0].parts |= map(.path = ($base + "/" + (.path | sub(".*/"; ""))))
' "$man" > "manifest$v.json"
cat "manifest$v.json"
gh release upload beta-fw "manifest$v.json" -R "${{ github.repository }}" --clobber
find "$src" -name '*.bin' -print -exec \
gh release upload beta-fw {} -R "${{ github.repository }}" --clobber \;
done
echo "Beta assets published."
9 changes: 8 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ jobs:
pull-requests: write
with:
device-name: temp-1
# The Minimal yamls are the end-user images served at firmware*/ (OTA
# updates and dashboard adoption). The improv images move to *-factory/
# and are only used for first flashes via the web installer.
yaml-files: |
Integrations/ESPHome/TEMP-1_Minimal.yaml
Integrations/ESPHome/TEMP-1B_Minimal.yaml
Integrations/ESPHome/TEMP-1_Minimal_R2.yaml
Integrations/ESPHome/TEMP-1B_Minimal_R2.yaml
Integrations/ESPHome/TEMP-1.yaml
Integrations/ESPHome/TEMP-1B.yaml
Integrations/ESPHome/TEMP-1_R2.yaml
Integrations/ESPHome/TEMP-1B_R2.yaml
firmware-names: "1:firmware,1B:firmware-b,1_R2:firmware2,1B_R2:firmware-b2"
firmware-names: "1_Minimal:firmware,1B_Minimal:firmware-b,1_Minimal_R2:firmware2,1B_Minimal_R2:firmware-b2,1:firmware-factory,1B:firmware-b-factory,1_R2:firmware2-factory,1B_R2:firmware-b2-factory"
core-yaml-path: Integrations/ESPHome/Core.yaml
esphome-version: stable
# Bypass check if manually triggered with bypass option
Expand Down
1 change: 1 addition & 0 deletions Integrations/ESPHome/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
# You can modify this file to suit your needs.
/.esphome/
/secrets.yaml
beta-channel/.esphome/
89 changes: 88 additions & 1 deletion Integrations/ESPHome/Core.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
substitutions:
version: "26.3.2.1"
version: "26.7.8.1"
# Firmware variant identity: overridden by the TEMP-1B / R2 images so each
# hardware variant tracks its own manifests ("", "-b", "2", "-b2").
variant_slug: ""
# 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" pre-release assets (beta branch builds).
stable_manifest_base: "https://apolloautomation.github.io/TEMP-1"
beta_manifest_base: "https://github.com/ApolloAutomation/TEMP-1/releases/download/beta-fw"

esp32:
variant: esp32c3
Expand Down Expand Up @@ -404,13 +416,74 @@ button:
icon: mdi:power-cycle
name: "ESP Reboot"

- platform: template
name: "Firmware Update"
id: update_firmware
icon: mdi:cloud-download
entity_category: "config"
on_press:
- logger.log: "Applying firmware based on selected channel"
# OTA download needs the device awake for its whole duration.
- lambda: |-
id(deep_sleep_1).prevent_deep_sleep();
# Free heap for the TLS download when BLE (improv) is active. Guarded
# so images without BLE compile the same YAML.
- lambda: |-
#ifdef USE_ESP32_BLE
if (esp32_ble::global_ble && esp32_ble::global_ble->is_active()) {
ESP_LOGI("firmware", "Disabling BLE for firmware update");
esp32_ble::global_ble->disable();
}
#endif
- delay: 3s
- script.execute: apply_ota_source
- script.wait: apply_ota_source
# The manifest fetch runs in its own task and YAML has no "fetch done"
# condition to wait on (update.is_available stays false for same-version
# switches), so give it a fixed window like R_PRO-1/CAST-1 do.
- delay: 5s
- update.perform:
id: update_http_request
force_update: true
# Only reached if the update did not start (e.g. manifest unreachable).
- lambda: |-
#ifdef USE_ESP32_BLE
if (esp32_ble::global_ble) {
ESP_LOGI("firmware", "Re-enabling BLE (no update performed)");
esp32_ble::global_ble->enable();
}
#endif
- if:
condition:
and:
- switch.is_off: prevent_sleep
- binary_sensor.is_off: ota_mode
then:
- lambda: |-
id(deep_sleep_1).allow_deep_sleep();

- platform: factory_reset
disabled_by_default: True
name: "Factory Reset ESP"
id: factory_reset_all


select:
- platform: template
name: "Firmware Channel"
id: firmware_channel
icon: mdi:source-branch
entity_category: "config"
optimistic: true
restore_value: true
options:
- "Stable"
- "Beta"
initial_option: "${firmware_channel_default}"
on_value:
then:
- script.execute: apply_ota_source

- platform: template
name: "Select Probe"
optimistic: true
Expand Down Expand Up @@ -505,6 +578,20 @@ text_sensor:
entity_category: "diagnostic"

script:
- id: apply_ota_source
# Sets the OTA manifest URL from the Firmware Channel select for this
# hardware variant (${variant_slug}).
# Stable = GitHub Pages, Beta = rolling "beta" release assets.
then:
- lambda: |-
const bool beta = id(firmware_channel).current_option() == "Beta";
std::string url = beta
? "${beta_manifest_base}/manifest${variant_slug}.json"
: "${stable_manifest_base}/firmware${variant_slug}/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: configureSourceSensorPolling
then:
- if:
Expand Down
9 changes: 6 additions & 3 deletions Integrations/ESPHome/TEMP-1.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
substitutions:
source_sensor_resistance: 100kOhm
firmware_update_manifest_url: https://apolloautomation.github.io/TEMP-1/firmware/manifest.json
# Firmware variant identity: drives the OTA manifest paths in Core.yaml.
variant_slug: ""

esphome:
name: "apollo-temp-1"
Expand Down Expand Up @@ -113,11 +114,13 @@ web_server:

update:
- platform: http_request
id: firmware_update
id: update_http_request
name: Firmware Update
source: ${firmware_update_manifest_url}
source: ${stable_manifest_base}/firmware${variant_slug}/manifest.json

wifi:
on_connect:
- component.update: update_http_request
id: wifi_1
ap:
ssid: "Apollo TEMP1 Hotspot"
Expand Down
9 changes: 6 additions & 3 deletions Integrations/ESPHome/TEMP-1B.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
substitutions:
source_sensor_resistance: 100kOhm
firmware_update_manifest_url: https://apolloautomation.github.io/TEMP-1/firmware-b/manifest.json
# Firmware variant identity: drives the OTA manifest paths in Core.yaml.
variant_slug: "-b"

esphome:
name: "apollo-temp-1b"
Expand Down Expand Up @@ -111,11 +112,13 @@ web_server:

update:
- platform: http_request
id: firmware_update
id: update_http_request
name: Firmware Update
source: ${firmware_update_manifest_url}
source: ${stable_manifest_base}/firmware${variant_slug}/manifest.json

wifi:
on_connect:
- component.update: update_http_request
id: wifi_1
ap:
ssid: "Apollo TEMP1B Hotspot"
Expand Down
14 changes: 14 additions & 0 deletions Integrations/ESPHome/TEMP-1B_BLE.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
substitutions:
variant_slug: "-b"
source_sensor_resistance: 100kOhm

esphome:
Expand Down Expand Up @@ -86,10 +87,23 @@ dashboard_import:
ota:
- platform: esphome
id: ota_esphome
- platform: http_request
id: ota_managed

http_request:
verify_ssl: true

update:
- platform: http_request
id: update_http_request
name: Firmware Update
source: ${stable_manifest_base}/firmware${variant_slug}/manifest.json

safe_mode:

wifi:
on_connect:
- component.update: update_http_request
ap:
ssid: "Apollo TEMP1 Hotspot"

Expand Down
1 change: 1 addition & 0 deletions Integrations/ESPHome/TEMP-1B_BLE_R2.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
substitutions:
variant_slug: "-b2"
source_sensor_resistance: 3.3kOhm

packages:
Expand Down
21 changes: 17 additions & 4 deletions Integrations/ESPHome/TEMP-1B_Minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ substitutions:
source_sensor_resistance: 100kOhm

esphome:
name: "apollo-temp-1b-minimal"
friendly_name: Apollo TEMP-1B Minimal
comment: Apollo TEMP-1B Minimal
name: "apollo-temp-1b"
friendly_name: Apollo TEMP-1B
comment: Apollo TEMP-1B
name_add_mac_suffix: true
project:
name: "ApolloAutomation.TEMP-1B_Minimal"
name: "ApolloAutomation.TEMP-1B"
version: "${version}"

min_version: 2025.11.0
Expand Down Expand Up @@ -85,12 +85,25 @@ safe_mode:
ota:
- platform: esphome
id: ota_esphome
- platform: http_request
id: ota_managed

http_request:
verify_ssl: true

update:
- platform: http_request
id: update_http_request
name: Firmware Update
source: ${stable_manifest_base}/firmware${variant_slug}/manifest.json

web_server:
port: 80
version: 3

wifi:
on_connect:
- component.update: update_http_request
id: wifi_1
ap:
ssid: "Apollo TEMP1B Hotspot"
Expand Down
5 changes: 3 additions & 2 deletions Integrations/ESPHome/TEMP-1B_Minimal_R2.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
substitutions:
variant_slug: "-b2"
source_sensor_resistance: 3.3kOhm

packages:
TEMP_1B_Minimal: !include "TEMP-1B_Minimal.yaml"

esphome:
name: "apollo-temp-1bminimalr2"
name: "apollo-temp-1b-42"
project:
name: "Apollo.TEMP-1B_Minimal_R2"
name: "Apollo.TEMP-1B_R2"
version: "${version}"

dashboard_import:
Expand Down
Loading