Skip to content

Merge branch 'main' of https://github.com/trip5/EspHome-Led-PixelClock #7

Merge branch 'main' of https://github.com/trip5/EspHome-Led-PixelClock

Merge branch 'main' of https://github.com/trip5/EspHome-Led-PixelClock #7

name: Build and Release Firmware
on:
push:
tags:
- '*'
workflow_dispatch:
permissions:
contents: write
jobs:
build-firmware:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install yq
run: |
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install ESPHome
run: |
pip install esphome
- name: Download font files
run: |
echo "📥 Downloading font files from Matrix-Fonts repository..."
mkdir -p generated_yamls/fonts
curl -L -o generated_yamls/fonts/MatrixChunky8X.bdf "https://github.com/trip5/Matrix-Fonts/raw/refs/heads/main/8-series/MatrixChunky8X.bdf"
curl -L -o generated_yamls/fonts/MatrixLight8X.bdf "https://github.com/trip5/Matrix-Fonts/raw/refs/heads/main/8-series/MatrixLight8X.bdf"
echo "✅ Downloaded font files to generated_yamls/fonts/:"
ls -la generated_yamls/fonts/
- name: Get version tag
id: get_version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION=$(yq eval '.substitutions.project_version' EHLPClock.yaml | tr -d '"')
TAG="${VERSION}"
echo "Extracted version from YAML: ${VERSION}"
else
TAG=${GITHUB_REF#refs/tags/}
VERSION=${TAG#v}
echo "Using git tag: ${TAG}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Final version: ${VERSION}"
- name: Generate language variants
run: |
echo "🔄 Generating language-specific YAML files..."
mkdir -p generated_yamls
mkdir -p generated_yamls/base
echo "🔧 Preparing base YAML for language merging..."
cp EHLPClock.yaml generated_yamls/base/EHLPClock-base.yaml
cp EHLPClock-HA.yaml generated_yamls/base/EHLPClock-HA-base.yaml
for base_file in generated_yamls/base/EHLPClock-base.yaml generated_yamls/base/EHLPClock-HA-base.yaml; do
sed -i 's/- ssid: !secret wifi_ssid/# - ssid: !secret wifi_ssid/' "$base_file"
sed -i 's/password: !secret wifi_password/# password: !secret wifi_password/' "$base_file"
sed -i '/password: !secret ap_password/d' "$base_file"
sed -i '/password: !secret ota_password/d' "$base_file"
sed -i '/key: !secret encryption_key/d' "$base_file"
done
for base_name in EHLPClock EHLPClock-HA; do
for lang_file in language_filters/*.yaml; do
if [ -f "$lang_file" ]; then
lang_name=$(basename "$lang_file" .yaml)
output_file="generated_yamls/${base_name}-${lang_name}.yaml"
echo "📝 Creating ${output_file} (English + ${lang_name})..."
yq eval-all '
select(fileIndex == 0) as $base |
select(fileIndex == 1) as $lang |
($lang.font // [] | map(.id)) as $lang_font_ids |
$base * $lang |
.font = (
($base.font // [] | map(select(.id as $id | $lang_font_ids | contains([$id]) | not))) +
($lang.font // [])
) |
.text_sensor = (
($base.text_sensor // [] | map(select(.id != "time_text" and .id != "date_text" and .id != "dateA_text"))) +
($lang.text_sensor // [])
)
' "generated_yamls/base/${base_name}-base.yaml" "$lang_file" > "$output_file"
echo "✅ Generated ${output_file}"
fi
done
done
echo "🧹 Cleaning timezone offset code from HA versions..."
for ha_file in generated_yamls/EHLPClock-HA-*.yaml; do
if [ -f "$ha_file" ]; then
echo "Cleaning timezone references from $ha_file"
sed -i '/if (id(tzoffset_on)/,/^[[:space:]]*}/d' "$ha_file"
sed -i '/tzoffset_on\|tzoffset\.state/d' "$ha_file"
sed -i '/delete.*HA version/d' "$ha_file"
echo "✅ Cleaned $ha_file"
fi
done
echo "📦 Generated firmware files:"
ls -la firmware/ || echo "No firmware directory created"
- name: Validate YAML files
run: |
echo "🔍 Validating generated YAML files..."
echo "📂 Checking downloaded font files:"
ls -la generated_yamls/fonts/
file generated_yamls/fonts/* || echo "No font files found"
for yaml_file in generated_yamls/*.yaml; do
echo "Validating $yaml_file..."
esphome config "$yaml_file"
done
echo "✅ All YAML files are valid"
- name: Compile ESPHome firmwares
run: |
echo "🔨 Compiling ESPHome firmwares..."
mkdir -p firmware
for yaml_file in generated_yamls/*.yaml; do
filename=$(basename "$yaml_file" .yaml)
echo "🔨 Building ${filename}..."
# Clean build directory to prevent mix-ups
rm -rf generated_yamls/.esphome/build/*
# Compile the firmware
esphome compile "$yaml_file"
device_name=$(find generated_yamls/.esphome/build/ -maxdepth 1 -type d ! -name "build" -printf "%f\n" 2>/dev/null | head -1)
if [ -z "$device_name" ]; then
device_name=$(yq eval '.substitutions.name' "$yaml_file" | tr -d '"')
fi
possible_paths=(
"generated_yamls/.esphome/build/${device_name}/.pioenvs/${device_name}/firmware.bin"
".pioenvs/${device_name}/firmware.bin"
"${device_name}/.pioenvs/${device_name}/firmware.bin"
".esphome/build/${device_name}/.pioenvs/${device_name}/firmware.bin"
)
binary_found=false
for binary_path in "${possible_paths[@]}"; do
if [ -f "$binary_path" ]; then
cp "$binary_path" "firmware/${filename}.bin"
echo "✅ Copied ${filename}.bin from $binary_path"
binary_found=true
break
fi
done
if [ "$binary_found" = false ]; then
echo "❌ Binary not found for ${filename}"
echo "Searched in:"
for path in "${possible_paths[@]}"; do
echo " - $path"
done
find . -name "firmware.bin" -type f 2>/dev/null || echo "No firmware.bin files found anywhere"
fi
done
echo "🔄 Renaming HA firmware files..."
for bin_file in firmware/EHLPClock-HA-*.bin; do
if [ -f "$bin_file" ]; then
lang=$(basename "$bin_file" | sed 's/EHLPClock-HA-\(.*\)\.bin/\1/')
new_name="firmware/EHLPClock-${lang}-HA.bin"
mv "$bin_file" "$new_name"
echo "Renamed $(basename "$bin_file") -> $(basename "$new_name")"
fi
done
echo "📦 Generated firmware files:"
ls -la firmware/ || echo "No firmware directory created"
- name: Create firmware manifests
run: |
echo "📝 Creating firmware manifests..."
rm -rf docs/manifests
mkdir -p docs/manifests
for bin_file in $(ls -1 firmware/*.bin); do
if [ -f "$bin_file" ]; then
filename=$(basename "$bin_file")
if [[ "$filename" == *"-HA.bin" ]]; then
lang_name=$(echo "$filename" | sed 's/EHLPClock-\(.*\)-HA\.bin/\1/')
variant_id="${lang_name}-HA"
else
lang_name=$(echo "$filename" | sed 's/EHLPClock-\([^.]*\)\.bin/\1/')
variant_id="${lang_name}"
fi
manifest_file="docs/manifests/${variant_id}-manifest.json"
echo '{' > "$manifest_file"
echo ' "name": "EspHome-Led-PixelClock",' >> "$manifest_file"
echo ' "version": "${{ steps.get_version.outputs.version }}",' >> "$manifest_file"
echo ' "home_assistant_domain": "esphome",' >> "$manifest_file"
echo ' "funding_url": "https://github.com/sponsors/trip5",' >> "$manifest_file"
echo ' "builds": [' >> "$manifest_file"
echo ' {' >> "$manifest_file"
echo ' "chipFamily": "ESP8266",' >> "$manifest_file"
echo ' "parts": [' >> "$manifest_file"
echo ' {' >> "$manifest_file"
echo " \"path\": \"../firmware/${filename}\"," >> "$manifest_file"
echo ' "offset": 0' >> "$manifest_file"
echo ' }' >> "$manifest_file"
echo ' ]' >> "$manifest_file"
echo ' }' >> "$manifest_file"
echo ' ]' >> "$manifest_file"
echo '}' >> "$manifest_file"
echo "Created manifest: $manifest_file"
fi
done
BUILD_DATE=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
echo '{' > docs/firmware-info.json
echo ' "project": "EspHome-Led-PixelClock",' >> docs/firmware-info.json
echo ' "version": "${{ steps.get_version.outputs.version }}",' >> docs/firmware-info.json
echo " \"build_date\": \"${BUILD_DATE}\"," >> docs/firmware-info.json
echo ' "variants": [' >> docs/firmware-info.json
FIRST=true
for bin_file in $(ls -1 firmware/*.bin); do
if [ -f "$bin_file" ]; then
filename=$(basename "$bin_file")
if [[ "$filename" == *"-HA.bin" ]]; then
lang_name=$(echo "$filename" | sed 's/EHLPClock-\(.*\)-HA\.bin/\1/')
display_name="${lang_name} - Home Assistant"
variant_id="${lang_name}-HA"
else
lang_name=$(echo "$filename" | sed 's/EHLPClock-\([^.]*\)\.bin/\1/')
display_name="${lang_name}"
variant_id="${lang_name}"
fi
if [ "$FIRST" = "false" ]; then
echo " ," >> docs/firmware-info.json
fi
FIRST=false
echo ' {' >> docs/firmware-info.json
echo " \"name\": \"${display_name}\"," >> docs/firmware-info.json
echo " \"manifest\": \"manifests/${variant_id}-manifest.json\"," >> docs/firmware-info.json
echo " \"description\": \"English + ${lang_name} firmware\"" >> docs/firmware-info.json
echo ' }' >> docs/firmware-info.json
fi
done
echo ' ]' >> docs/firmware-info.json
echo '}' >> docs/firmware-info.json
echo "✅ Created firmware manifests and info"
- name: Commit manifest files to docs
run: |
git fetch origin main
git checkout main
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add docs/manifests/*.json docs/firmware-info.json
git commit -m "Update firmware manifests for ${{ steps.get_version.outputs.version }} [skip ci]" || echo "No changes to commit"
git push origin main || echo "Nothing to push"
- name: Upload firmware artifacts
uses: actions/upload-artifact@v4
with:
name: firmware-binaries
path: |
firmware/*.bin
docs/firmware-info.json
docs/manifests/*.json
retention-days: 90
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.get_version.outputs.tag }}
name: "${{ steps.get_version.outputs.tag }}"
body: |
Compiled firmware binaries for EspHome-Led-PixelClock with different second-language options (all have English as a first language).
You can download the firmware and flash yourself or you can use my [Web Installer](https://trip5.github.io/EspHome-Led-PixelClock/firmware.html).
These firmwares can get Wi-fi SSID and password through Improv via Serial or through the captive portal.
You can use the tool provided above or the official one at [Improv-wifi](https://www.improv-wifi.com/) (click on 'Improv via Serial').
The captive portal will make a hotspot with the name of the clock. Connect to it and visit http://192.168.4.1 to configure the wi-fi.
files: |
firmware/*.bin
fail_on_unmatched_files: false
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}