Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
296fa2e
Rework Original into an HTTPS webhook tally counter
impuls42 Jul 25, 2026
3573ef3
CI: include ota_data_initial.bin in the artifact bundle
impuls42 Jul 25, 2026
1ba7557
CI: flatten the flash-image artifact
impuls42 Jul 25, 2026
1b7bb02
Derive the setup AP password from the serial, not the random id
impuls42 Jul 25, 2026
b5b29ef
Route the debug build's console to USB CDC, add an Awake Mode toggle
impuls42 Jul 26, 2026
14e17a3
Make the button LED report delivery, not wakefulness
impuls42 Jul 26, 2026
856b10c
Lay the counters out as columns, one per counter
impuls42 Jul 26, 2026
6a9dcfc
CI: build and publish the debug environment too
impuls42 Jul 26, 2026
e869062
Allow baking any MDI icon in at build time, and emit 1-bit BMPs
impuls42 Jul 26, 2026
ced8d9c
Source icons from Templarian/MaterialDesign, scale counter text up
impuls42 Jul 26, 2026
85c918e
Build the SPIFFS image with ESP-IDF parameters, not ESP8266 Arduino ones
impuls42 Jul 26, 2026
7d4d67f
Revert the USB CDC console: it is not supported alongside TinyUSB
impuls42 Jul 26, 2026
aeda465
Place counter totals like icons, not like text
impuls42 Jul 26, 2026
111f523
Redraw the count on press, not on delivery
impuls42 Jul 26, 2026
23ea594
Add scheduled counter reset, clocked from the webhook response
impuls42 Jul 26, 2026
3198300
Fix review findings: webhook task race, shared state, add tests
impuls42 Jul 26, 2026
7c1e84e
CI: run the host unit tests before building firmware
impuls42 Jul 26, 2026
aad92ec
Stamp the commit sha into the firmware, the filesystem and the artifacts
impuls42 Jul 26, 2026
89e4949
CI: stamp the branch head, not the PR merge commit
impuls42 Jul 26, 2026
76a7c04
Serialise NVS access - fixes Wi-Fi failing intermittently
impuls42 Jul 26, 2026
bd4f8e4
Add a Wi-Fi country setting so channels 12-13 are usable
impuls42 Jul 26, 2026
ab84db2
Put the Wi-Fi country field in the Wi-Fi-only portal too
impuls42 Jul 26, 2026
d608eae
Restart when the Wi-Fi region changes, and log whether it persists
impuls42 Jul 26, 2026
5ac1f6d
Read the Wi-Fi region when its form is submitted, not after the portal
impuls42 Jul 26, 2026
989e503
Log the Wi-Fi disconnect reason code
impuls42 Jul 26, 2026
99f387e
Stop restarting when the Wi-Fi region changes
impuls42 Jul 27, 2026
700aca3
Present a USB CDC device while running, so USB-C can reset the board
impuls42 Jul 27, 2026
02722e8
Add a serial command console for diagnostics and testing
impuls42 Jul 27, 2026
172737b
Do not clear the counters when local time moves backwards
impuls42 Jul 27, 2026
0395b95
Test the reset boundary on a timer, not only on a press or a wake
impuls42 Jul 27, 2026
06a9447
Add an awake-mode console command
impuls42 Jul 27, 2026
ce72fab
Deliver the reset report and heartbeat before dropping the link
impuls42 Jul 27, 2026
59f1212
Recover the clock after a reset, and stop scheduling wakes from a bad…
impuls42 Jul 27, 2026
04a4ea7
Feed the watchdog between webhook sends
impuls42 Jul 27, 2026
179a502
Document the console, and that the webhook response carries the clock
impuls42 Jul 27, 2026
5651d0d
Address code review: keep webhook work on the main task, fix reset bo…
impuls42 Jul 27, 2026
3d33168
Make the reset-period rule a pure function, and test it
impuls42 Jul 27, 2026
072f7b0
Build the serial console into debug images only
impuls42 Jul 27, 2026
9d34881
Bring the README and guide back in line with the firmware
impuls42 Jul 27, 2026
a85cd6d
Say which serial port to flash, and why the obvious one is wrong
impuls42 Jul 27, 2026
9ae0169
Tell the three esptool failures apart
impuls42 Jul 27, 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
16 changes: 0 additions & 16 deletions .github/workflows/ci.yml

This file was deleted.

157 changes: 157 additions & 0 deletions .github/workflows/firmware.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: firmware

# Upstream had no firmware build in CI at all — only a docs deploy — which is
# how its `pro_*` targets drifted into a state that could not compile. This is
# the gate that stops that happening again.

on:
push:
branches: [main, master]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
# ADR-0007 Form 2. This repo is public, so it cannot reach the org ARC
# runners (the Default runner group sets allows_public_repositories=false)
# and cannot read CI_RUNNER_MODE, which is a private-visibility org var.
# The expression therefore resolves to ubuntu-latest today — free and
# unmetered for public repos — but picks up ARC automatically if this
# repo is ever made private. Keep it byte-identical to the ADR form so
# the org drift gate matches it.
runs-on: ${{ vars.CI_RUNNER_MODE == 'arc' && (vars.SELF_HOSTED_LABEL || 'arc-se-org-shared') || 'ubuntu-latest' }}

steps:
- uses: actions/checkout@v4
with:
# pre_script.py and make_icons.py stamp the short sha into the
# firmware and the SPIFFS image, so the checkout needs real git
# metadata rather than a detached blob.
fetch-depth: 0
# On a pull_request event the default checkout is a merge commit
# that exists nowhere in the branch, so a device would report a
# sha nobody can look up. Build the branch head instead. The
# trade-off is that CI tests the branch as-is rather than merged
# with the base, which is what a build stamp should describe.
ref: ${{ github.event.pull_request.head.sha || github.sha }}

# Artifact names carry the sha so successive downloads land as
# homebuttons-original-<sha>.zip instead of "firmware-original (3)".
- name: Build id
id: build_id
run: echo "sha=$(git rev-parse --short=8 HEAD)" >> "$GITHUB_OUTPUT"

- uses: actions/setup-python@v5
with:
python-version: '3.12'

# The toolchain is ~1 GB and the ESP-IDF/Arduino build pulls it fresh
# on every cold runner, so this cache is most of the wall-clock time.
- name: Cache PlatformIO
uses: actions/cache@v4
with:
path: |
~/.platformio
~/.cache/pip
key: pio-${{ runner.os }}-${{ hashFiles('Firmware/HomeButtonsArduino/platformio.ini') }}
restore-keys: pio-${{ runner.os }}-

- name: Install PlatformIO
run: pip install --upgrade platformio

# make_icons.py rasterises the MDI SVGs listed in icons.txt. Normally
# already on the runner image; install only if it is not, rather than
# paying for an apt update on every run.
- name: Ensure ImageMagick
run: |
if ! command -v convert >/dev/null && ! command -v magick >/dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq imagemagick
fi
(magick -version || convert -version) 2>/dev/null | head -1

# Both environments are built and published. They are not
# interchangeable: original_debug routes the console to USB CDC and
# uses QIO flash mode, so it has its own bootloader.bin as well as its
# own firmware.bin.
# Host-side tests for the pure-logic modules. Runs before the firmware
# build because it is seconds rather than minutes, and a calendar bug
# here would otherwise only show up on a device weeks later.
- name: Unit tests
working-directory: Firmware/HomeButtonsArduino
run: pio test -e native

- name: Build firmware
working-directory: Firmware/HomeButtonsArduino
run: pio run -e original_release -e original_debug

- name: Build SPIFFS image
working-directory: Firmware/HomeButtonsArduino
run: |
python tools/make_icons.py
pio run -e original_release -e original_debug -t buildfs

# The app partition was 95.8% full before this fork stripped MQTT and
# the icon downloader. Fail loudly rather than discovering at flash
# time that the image no longer fits.
- name: Check flash headroom
working-directory: Firmware/HomeButtonsArduino
run: |
set -euo pipefail
LIMIT=$((0x1A0000))
FAIL=0
for ENV in original_release original_debug; do
SIZE=$(stat -c%s ".pio/build/${ENV}/firmware.bin")
PCT=$((SIZE * 100 / LIMIT))
echo "${ENV}: ${SIZE} of ${LIMIT} bytes (${PCT}%)"
echo "\`${ENV}\`: ${SIZE} / ${LIMIT} bytes (${PCT}%)" >> "$GITHUB_STEP_SUMMARY"
if [ "$PCT" -ge 90 ]; then
echo "::error::${ENV} firmware is ${PCT}% of the app partition"
FAIL=1
fi
done
exit "$FAIL"

# upload-artifact derives the archive layout from the common ancestor of
# its paths, so listing files by their build-tree location buries them
# under .pio/build/<env>/ in the download. Stage each environment into
# its own flat directory instead, so unzipping either artifact gives
# you the images side by side, ready to flash.
#
# Two artifacts rather than one with subdirectories: both environments
# produce a firmware.bin and a bootloader.bin, so a single flat
# directory cannot hold both, and subdirectories would reintroduce the
# nesting this exists to avoid.
- name: Stage flash images
working-directory: Firmware/HomeButtonsArduino
run: |
set -euo pipefail
for ENV in original_release original_debug; do
mkdir -p "dist/${ENV}"
cp ".pio/build/${ENV}/bootloader.bin" \
".pio/build/${ENV}/partitions.bin" \
".pio/build/${ENV}/ota_data_initial.bin" \
".pio/build/${ENV}/firmware.bin" \
".pio/build/${ENV}/spiffs.bin" \
partitions.csv \
data/build.txt \
"dist/${ENV}/"
echo "--- dist/${ENV} ---"
ls -l "dist/${ENV}"
done

- uses: actions/upload-artifact@v4
with:
name: homebuttons-original-${{ steps.build_id.outputs.sha }}
path: Firmware/HomeButtonsArduino/dist/original_release/
if-no-files-found: error

# Console on USB CDC - flash this one when you want logs over the
# USB-C cable instead of the UART pins on the debug header.
- uses: actions/upload-artifact@v4
with:
name: homebuttons-original-debug-${{ steps.build_id.outputs.sha }}
path: Firmware/HomeButtonsArduino/dist/original_debug/
if-no-files-found: error
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,6 @@ $RECYCLE.BIN/
# End of https://www.toptal.com/developers/gitignore/api/c++,macos,windows,visualstudiocode,python

### Project specific ###

# Generated by Firmware/HomeButtonsArduino/tools/make_icons.py
Firmware/HomeButtonsArduino/data/
10 changes: 10 additions & 0 deletions Firmware/HomeButtonsArduino/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@ sdkconfig.mini_debug
sdkconfig.mini_release
sdkconfig.pro_release
sdkconfig.pro_debug

# Generated per-build and deleted by pre_script.py
sdkconfig.original_release
sdkconfig.original_debug

# CI artifact staging dir
dist/

# Generated by tools/make_icons.py alongside the icons
data/build.txt
21 changes: 21 additions & 0 deletions Firmware/HomeButtonsArduino/icons.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Material Design Icons baked into the SPIFFS image.
#
# One name per line. Browse and search names at:
# https://pictogrammers.com/library/mdi/
# Use the name exactly as shown there - lowercase and hyphenated.
#
# These are fetched at BUILD time by tools/make_icons.py and flashed into
# SPIFFS; the device never downloads anything at runtime. CI reads this
# file too, so anything listed here ends up in the published artifacts.
#
# A name that does not exist fails the build rather than turning into a
# placeholder glyph you would only notice on the device.
#
# `plus` and `minus` are drawn locally by the script and are always
# present - no need to list them.
#
# Reference one from a button label as `mdi:food-drumstick`, or
# `mdi:food-drumstick Wings` for icon plus text.

food-drumstick
dog-service
13 changes: 9 additions & 4 deletions Firmware/HomeButtonsArduino/partitions.csv
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# Name, Type, SubType, Offset, Size, Flags
# Upstream gave each app slot 0x140000 and SPIFFS 0x160000. The baseline
# build already used 95.8% of an app slot, and the runtime icon downloader
# is gone, so SPIFFS only has to hold a handful of pre-loaded BMPs. Space
# moved from SPIFFS to the app slots to make room for the mbedTLS
# certificate bundle.
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x140000,
app1, app, ota_1, 0x150000,0x140000,
spiffs, data, spiffs, 0x290000,0x160000,
coredump, data, coredump,0x3F0000,0x10000,
app0, app, ota_0, 0x10000, 0x1A0000,
app1, app, ota_1, 0x1B0000,0x1A0000,
spiffs, data, spiffs, 0x350000,0xA0000,
coredump, data, coredump,0x3F0000,0x10000,
Loading
Loading