Skip to content

Commit 1793be9

Browse files
committed
fix: package firmware as zip files to avoid release filename conflicts
- Create individual zip files for each firmware - Create combined all-firmware.zip - Update release body with correct GitHub Pages URL - Only upload .zip files to avoid duplicate filename errors
1 parent 0951947 commit 1793be9

File tree

5 files changed

+94
-7
lines changed

5 files changed

+94
-7
lines changed

.github/workflows/build-firmware.yml

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ on:
2626

2727
env:
2828
ARDUINO_CLI_VERSION: "0.35.3"
29+
ESP32_CORE_VERSION: "3.3.4" # Lock ESP32 Core version for build consistency | 锁定 ESP32 Core 版本以确保构建一致性
2930

3031
jobs:
3132
build:
@@ -76,9 +77,11 @@ jobs:
7677
arduino-cli config init
7778
arduino-cli config add board_manager.additional_urls "${{ matrix.platform_url }}"
7879
79-
# Update index and install platform | 更新索引并安装平台
80+
# Update index and install platform with locked version | 更新索引并安装锁定版本的平台
8081
arduino-cli core update-index
81-
arduino-cli core install ${{ matrix.platform }}
82+
arduino-cli core install ${{ matrix.platform }}@${{ env.ESP32_CORE_VERSION }}
83+
84+
echo "Installed ESP32 Core version: ${{ env.ESP32_CORE_VERSION }}"
8285
8386
# Install required libraries | 安装所需库
8487
arduino-cli lib install "ArduinoJson"
@@ -120,6 +123,27 @@ jobs:
120123
fi
121124
done
122125
126+
# Copy boot_app0.bin from ESP32 Core (required for OTA boot selection)
127+
# 从 ESP32 Core 复制 boot_app0.bin(OTA 启动选择所需)
128+
# This file is at offset 0xe000 and is needed for proper boot sequence
129+
# 此文件在偏移地址 0xe000,正确启动序列所需
130+
ESP32_CORE_PATH=$(find ~/.arduino15/packages/esp32/hardware/esp32 -maxdepth 1 -type d -name "${{ env.ESP32_CORE_VERSION }}" | head -1)
131+
if [ -n "$ESP32_CORE_PATH" ] && [ -f "$ESP32_CORE_PATH/tools/partitions/boot_app0.bin" ]; then
132+
cp "$ESP32_CORE_PATH/tools/partitions/boot_app0.bin" ./boot_app0.bin
133+
echo "✓ Copied boot_app0.bin from ESP32 Core"
134+
else
135+
echo "⚠ Warning: boot_app0.bin not found, trying alternative path..."
136+
# Alternative search | 备选搜索路径
137+
BOOT_APP0=$(find ~/.arduino15/packages/esp32 -name "boot_app0.bin" -type f | head -1)
138+
if [ -n "$BOOT_APP0" ]; then
139+
cp "$BOOT_APP0" ./boot_app0.bin
140+
echo "✓ Copied boot_app0.bin from: $BOOT_APP0"
141+
else
142+
echo "✗ Error: boot_app0.bin not found!"
143+
exit 1
144+
fi
145+
fi
146+
123147
# List final files | 列出最终文件
124148
echo "Final firmware files:"
125149
ls -la
@@ -135,6 +159,7 @@ jobs:
135159
CHIP_FAMILY="ESP32-C6"
136160
BOOTLOADER_OFFSET=0
137161
PARTITIONS_OFFSET=32768 # 0x8000
162+
BOOT_APP0_OFFSET=57344 # 0xe000 - OTA boot selection | OTA 启动选择
138163
FIRMWARE_OFFSET=65536 # 0x10000
139164
140165
if [[ "${{ matrix.board }}" == *"esp32s3"* ]] || [[ "${{ matrix.board }}" == *"XIAO_ESP32S3"* ]]; then
@@ -159,8 +184,11 @@ jobs:
159184
160185
echo "Chip Family: ${CHIP_FAMILY}"
161186
echo "Bootloader Offset: ${BOOTLOADER_OFFSET}"
187+
echo "Boot App0 Offset: ${BOOT_APP0_OFFSET}"
162188
163-
# Create manifest.json | 创建 manifest.json
189+
# Create manifest.json with all 4 binary files | 创建包含所有 4 个二进制文件的 manifest.json
190+
# Flash layout: bootloader -> partitions -> boot_app0 -> firmware
191+
# Flash 布局:bootloader -> partitions -> boot_app0 -> firmware
164192
cat > manifest.json << EOF
165193
{
166194
"name": "${{ matrix.firmware }}",
@@ -175,6 +203,7 @@ jobs:
175203
"parts": [
176204
{ "path": "bootloader.bin", "offset": ${BOOTLOADER_OFFSET} },
177205
{ "path": "partitions.bin", "offset": ${PARTITIONS_OFFSET} },
206+
{ "path": "boot_app0.bin", "offset": ${BOOT_APP0_OFFSET} },
178207
{ "path": "firmware.bin", "offset": ${FIRMWARE_OFFSET} }
179208
]
180209
}
@@ -265,6 +294,26 @@ jobs:
265294
VERSION=$(date +'%Y.%m.%d')-$(git rev-parse --short HEAD)
266295
echo "version=$VERSION" >> $GITHUB_OUTPUT
267296
297+
- name: Package firmware for release
298+
run: |
299+
# Create zip files for each firmware to avoid filename conflicts
300+
# 为每个固件创建 zip 文件以避免文件名冲突
301+
cd firmware
302+
303+
for dir in */; do
304+
firmware_name="${dir%/}"
305+
echo "Packaging $firmware_name..."
306+
zip -r "${firmware_name}.zip" "$dir"
307+
done
308+
309+
# Also create a combined zip with all firmware | 同时创建包含所有固件的合并 zip
310+
cd ..
311+
zip -r "all-firmware.zip" firmware/
312+
mv all-firmware.zip firmware/
313+
314+
echo "Created packages:"
315+
ls -la firmware/*.zip
316+
268317
- name: Create Release
269318
uses: softprops/action-gh-release@v1
270319
with:
@@ -277,14 +326,20 @@ jobs:
277326
278327
### How to Flash | 如何烧录
279328
280-
Visit our [Web Flasher](https://your-github-username.github.io/hacs-devolop/flasher/) to flash firmware directly from your browser.
329+
Visit our [Web Flasher](https://limengdu.github.io/Seeed-Homeassistant-Discovery/flasher/) to flash firmware directly from your browser.
281330
282-
Or download the files and use ESP Web Tools manually.
331+
Or download the zip files and use ESP Web Tools manually.
283332
284333
### Included Firmware | 包含的固件
285334
286335
- IoTButtonV2_DeepSleep (ESP32-C6)
287336
- WiFiProvisioning (ESP32-C6)
337+
338+
### Downloads | 下载
339+
340+
- `all-firmware.zip` - All firmware in one package | 所有固件合集
341+
- `IoTButtonV2_DeepSleep.zip` - IoT Button V2 firmware only
342+
- `WiFiProvisioning.zip` - WiFi Provisioning demo only
288343
files: |
289-
firmware/**/*
344+
firmware/*.zip
290345

docs/flasher/build-local.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,21 @@ build_firmware() {
137137
# Clean up extra files | 清理多余文件
138138
rm -f *.elf *.map 2>/dev/null || true
139139

140+
# Copy boot_app0.bin from ESP32 Core (required for OTA boot selection)
141+
# 从 ESP32 Core 复制 boot_app0.bin(OTA 启动选择所需)
142+
local boot_app0_src=$(find "$HOME/Library/Arduino15/packages/esp32/hardware/esp32" -name "boot_app0.bin" -type f 2>/dev/null | head -1)
143+
if [ -z "$boot_app0_src" ]; then
144+
# Try Linux path | 尝试 Linux 路径
145+
boot_app0_src=$(find "$HOME/.arduino15/packages/esp32/hardware/esp32" -name "boot_app0.bin" -type f 2>/dev/null | head -1)
146+
fi
147+
148+
if [ -n "$boot_app0_src" ]; then
149+
cp "$boot_app0_src" ./boot_app0.bin
150+
echo -e "${GREEN} ✓ Copied boot_app0.bin${NC}"
151+
else
152+
echo -e "${YELLOW} ⚠ Warning: boot_app0.bin not found${NC}"
153+
fi
154+
140155
# Determine bootloader offset | 确定 bootloader 偏移
141156
local bootloader_offset=0
142157
case "$chip_family" in
@@ -148,7 +163,7 @@ build_firmware() {
148163
;;
149164
esac
150165

151-
# Create manifest.json | 创建 manifest.json
166+
# Create manifest.json with boot_app0.bin | 创建包含 boot_app0.bin 的 manifest.json
152167
cat > manifest.json << EOF
153168
{
154169
"name": "$name",
@@ -163,6 +178,7 @@ build_firmware() {
163178
"parts": [
164179
{ "path": "bootloader.bin", "offset": $bootloader_offset },
165180
{ "path": "partitions.bin", "offset": 32768 },
181+
{ "path": "boot_app0.bin", "offset": 57344 },
166182
{ "path": "firmware.bin", "offset": 65536 }
167183
]
168184
}

docs/flasher/firmware/IoTButtonV2_DeepSleep/manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
"path": "partitions.bin",
1818
"offset": 32768
1919
},
20+
{
21+
"path": "boot_app0.bin",
22+
"offset": 57344
23+
},
2024
{
2125
"path": "firmware.bin",
2226
"offset": 65536

docs/flasher/firmware/WiFiProvisioning/manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
"path": "partitions.bin",
1818
"offset": 32768
1919
},
20+
{
21+
"path": "boot_app0.bin",
22+
"offset": 57344
23+
},
2024
{
2125
"path": "firmware.bin",
2226
"offset": 65536

docs/flasher/generate-flasher.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,42 @@
2121

2222
# ESP32 chip family flash offsets | ESP32 芯片系列的 Flash 偏移地址
2323
# Different chips have different memory layouts | 不同芯片有不同的内存布局
24+
# boot_app0.bin at 0xe000 is required for OTA boot selection | 0xe000 处的 boot_app0.bin 是 OTA 启动选择所需
2425
CHIP_OFFSETS = {
2526
"ESP32": {
2627
"bootloader": 0x1000,
2728
"partitions": 0x8000,
29+
"boot_app0": 0xe000,
2830
"firmware": 0x10000
2931
},
3032
"ESP32-S2": {
3133
"bootloader": 0x1000,
3234
"partitions": 0x8000,
35+
"boot_app0": 0xe000,
3336
"firmware": 0x10000
3437
},
3538
"ESP32-S3": {
3639
"bootloader": 0x0,
3740
"partitions": 0x8000,
41+
"boot_app0": 0xe000,
3842
"firmware": 0x10000
3943
},
4044
"ESP32-C3": {
4145
"bootloader": 0x0,
4246
"partitions": 0x8000,
47+
"boot_app0": 0xe000,
4348
"firmware": 0x10000
4449
},
4550
"ESP32-C6": {
4651
"bootloader": 0x0,
4752
"partitions": 0x8000,
53+
"boot_app0": 0xe000,
4854
"firmware": 0x10000
4955
},
5056
"ESP32-H2": {
5157
"bootloader": 0x0,
5258
"partitions": 0x8000,
59+
"boot_app0": 0xe000,
5360
"firmware": 0x10000
5461
}
5562
}
@@ -79,6 +86,7 @@ def generate_manifest(firmware: dict, output_dir: str) -> None:
7986
"parts": [
8087
{"path": "bootloader.bin", "offset": offsets['bootloader']},
8188
{"path": "partitions.bin", "offset": offsets['partitions']},
89+
{"path": "boot_app0.bin", "offset": offsets['boot_app0']},
8290
{"path": "firmware.bin", "offset": offsets['firmware']}
8391
]
8492
}

0 commit comments

Comments
 (0)