Skip to content

Commit f0b779b

Browse files
committed
Corrige l'OTA GitHub pour distinguer les builds headless et ecran
1 parent 1fb53d0 commit f0b779b

6 files changed

Lines changed: 110 additions & 19 deletions

File tree

.github/workflows/release.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ jobs:
3939
run: pip install platformio
4040

4141
- name: Build firmware
42-
run: pio run -e soundpanel7_ota
42+
run: |
43+
pio run -e soundpanel7_ota
44+
pio run -e soundpanel7_headless_ota
4345
4446
- name: Generate release manifest
4547
env:
@@ -51,6 +53,7 @@ jobs:
5153
--repository "${REPOSITORY}" \
5254
--published-at "${{ github.event.release.published_at }}" \
5355
--build-dir .pio/build/soundpanel7_ota \
56+
--headless-build-dir .pio/build/soundpanel7_headless_ota \
5457
--output .pio/build/soundpanel7_ota/release-manifest.json
5558
5659
- name: Upload release workflow artifact
@@ -61,6 +64,9 @@ jobs:
6164
.pio/build/soundpanel7_ota/firmware.bin
6265
.pio/build/soundpanel7_ota/bootloader.bin
6366
.pio/build/soundpanel7_ota/partitions.bin
67+
.pio/build/soundpanel7_headless_ota/firmware.bin
68+
.pio/build/soundpanel7_headless_ota/bootloader.bin
69+
.pio/build/soundpanel7_headless_ota/partitions.bin
6470
.pio/build/soundpanel7_ota/release-manifest.json
6571
6672
- name: Attach binaries to GitHub release
@@ -71,5 +77,8 @@ jobs:
7177
.pio/build/soundpanel7_ota/firmware.bin#soundpanel7_ota-firmware.bin \
7278
.pio/build/soundpanel7_ota/bootloader.bin#soundpanel7_ota-bootloader.bin \
7379
.pio/build/soundpanel7_ota/partitions.bin#soundpanel7_ota-partitions.bin \
80+
.pio/build/soundpanel7_headless_ota/firmware.bin#soundpanel7_headless_ota-firmware.bin \
81+
.pio/build/soundpanel7_headless_ota/bootloader.bin#soundpanel7_headless_ota-bootloader.bin \
82+
.pio/build/soundpanel7_headless_ota/partitions.bin#soundpanel7_headless_ota-partitions.bin \
7483
.pio/build/soundpanel7_ota/release-manifest.json#release-manifest.json \
7584
--clobber

RELEASING.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ If the current state is the one you want to publish, release:
3333

3434
```bash
3535
pio run -e soundpanel7_ota
36+
pio run -e soundpanel7_headless_ota
3637
```
3738

3839
4. Optionally validate the USB build too:
@@ -79,6 +80,9 @@ After a successful release build, useful firmware files are generated in:
7980
- `.pio/build/soundpanel7_ota/firmware.bin`
8081
- `.pio/build/soundpanel7_ota/bootloader.bin`
8182
- `.pio/build/soundpanel7_ota/partitions.bin`
83+
- `.pio/build/soundpanel7_headless_ota/firmware.bin`
84+
- `.pio/build/soundpanel7_headless_ota/bootloader.bin`
85+
- `.pio/build/soundpanel7_headless_ota/partitions.bin`
8286
- `.pio/build/soundpanel7_ota/release-manifest.json`
8387

8488
If GitHub Actions is enabled for the repository, publishing the GitHub release will automatically build the firmware and attach these files to the release.
@@ -94,7 +98,7 @@ The release workflow also publishes `release-manifest.json`.
9498
Its purpose is to give the device a stable machine-readable source for:
9599

96100
- latest version
97-
- OTA firmware URL
101+
- OTA firmware URLs per hardware profile
98102
- SHA-256 checksum
99103
- release metadata
100104

@@ -108,16 +112,28 @@ Current structure:
108112
"published_at": "2026-03-13T12:00:00Z",
109113
"release_url": "https://github.com/jjtronics/SoundPanel7/releases/tag/v0.2.0",
110114
"ota": {
111-
"name": "firmware.bin",
115+
"name": "soundpanel7_ota-firmware.bin",
112116
"type": "firmware",
113-
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/firmware.bin",
117+
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/soundpanel7_ota-firmware.bin",
118+
"sha256": "..."
119+
},
120+
"ota_screen": {
121+
"name": "soundpanel7_ota-firmware.bin",
122+
"type": "firmware",
123+
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/soundpanel7_ota-firmware.bin",
124+
"sha256": "..."
125+
},
126+
"ota_headless": {
127+
"name": "soundpanel7_headless_ota-firmware.bin",
128+
"type": "firmware",
129+
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/soundpanel7_headless_ota-firmware.bin",
114130
"sha256": "..."
115131
},
116132
"assets": [
117133
{
118-
"name": "firmware.bin",
134+
"name": "soundpanel7_ota-firmware.bin",
119135
"type": "firmware",
120-
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/firmware.bin",
136+
"url": "https://github.com/jjtronics/SoundPanel7/releases/download/v0.2.0/soundpanel7_ota-firmware.bin",
121137
"sha256": "..."
122138
}
123139
]
@@ -128,8 +144,8 @@ For the future update-check task, the recommended flow is:
128144

129145
1. fetch `release-manifest.json`
130146
2. compare `version` with the current firmware version
131-
3. use `ota.url` for download
132-
4. verify `ota.sha256` before applying the update
147+
3. choose the correct OTA entry for the current hardware profile
148+
4. verify the matching SHA-256 before applying the update
133149

134150
## Suggested first release notes
135151

custom_components/soundpanel7/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"iot_class": "local_polling",
99
"issue_tracker": "https://github.com/jjtronics/SoundPanel7/issues",
1010
"requirements": [],
11-
"version": "0.2.12",
11+
"version": "0.2.13",
1212
"zeroconf": [
1313
{
1414
"type": "_soundpanel7._tcp.local."

include/AppConfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#pragma once
33
#include <stdint.h>
44

5-
#define SOUNDPANEL7_VERSION "0.2.12"
5+
#define SOUNDPANEL7_VERSION "0.2.13"
66
#define SOUNDPANEL7_BUILD_DATE __DATE__ " " __TIME__
77

88
#ifndef SOUNDPANEL7_BUILD_ENV

src/ReleaseUpdateManager.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ String extractReleaseAssetField(const String& payload, const char* assetName, co
5757
const String scope = payload.substring(assetPos, nextAssetPos);
5858
return sp7json::parseString(scope, fieldName, def, false);
5959
}
60+
61+
const char* preferredReleaseFirmwareAssetName() {
62+
#if SOUNDPANEL7_HAS_SCREEN
63+
return "soundpanel7_ota-firmware.bin";
64+
#else
65+
return "soundpanel7_headless_ota-firmware.bin";
66+
#endif
67+
}
68+
69+
bool selectManifestOtaForCurrentProfile(const String& payload, String& otaUrl, String& otaSha256) {
70+
#if SOUNDPANEL7_HAS_SCREEN
71+
otaUrl = sp7json::parseString(payload, "otaScreenUrl", "", false);
72+
otaSha256 = sp7json::parseString(payload, "otaScreenSha256", "", false);
73+
#else
74+
otaUrl = sp7json::parseString(payload, "otaHeadlessUrl", "", false);
75+
otaSha256 = sp7json::parseString(payload, "otaHeadlessSha256", "", false);
76+
#endif
77+
if (!otaUrl.isEmpty() && otaSha256.length() == 64) return true;
78+
79+
otaUrl = sp7json::parseString(payload, "url", "", false);
80+
otaSha256 = sp7json::parseString(payload, "sha256", "", false);
81+
return !otaUrl.isEmpty() && otaSha256.length() == 64;
82+
}
6083
}
6184

6285
bool ReleaseUpdateManager::begin(NetManager* net) {
@@ -489,8 +512,14 @@ bool ReleaseUpdateManager::parseLatestReleaseApiPayload(const String& payload) {
489512
const String version = stripLeadingVersionPrefix(tag);
490513
const String publishedAt = sp7json::parseString(payload, "published_at", "", false);
491514
const String releaseUrl = sp7json::parseString(payload, "html_url", "", false);
492-
const String otaUrl = extractReleaseAssetField(payload, "firmware.bin", "browser_download_url", "");
493-
String otaSha256 = extractReleaseAssetField(payload, "firmware.bin", "digest", "");
515+
const char* preferredAssetName = preferredReleaseFirmwareAssetName();
516+
String otaUrl = extractReleaseAssetField(payload, preferredAssetName, "browser_download_url", "");
517+
String otaSha256 = extractReleaseAssetField(payload, preferredAssetName, "digest", "");
518+
519+
if (otaUrl.isEmpty() || otaSha256.isEmpty()) {
520+
otaUrl = extractReleaseAssetField(payload, "firmware.bin", "browser_download_url", "");
521+
otaSha256 = extractReleaseAssetField(payload, "firmware.bin", "digest", "");
522+
}
494523

495524
if (version.isEmpty()) {
496525
setError("latest release missing tag_name");
@@ -561,8 +590,9 @@ bool ReleaseUpdateManager::parseManifest(const String& payload) {
561590
String version = sp7json::parseString(payload, "version", "", false);
562591
String publishedAt = sp7json::parseString(payload, "published_at", "", false);
563592
String releaseUrl = sp7json::parseString(payload, "release_url", "", false);
564-
String otaUrl = sp7json::parseString(payload, "url", "", false);
565-
String otaSha256 = sp7json::parseString(payload, "sha256", "", false);
593+
String otaUrl;
594+
String otaSha256;
595+
selectManifestOtaForCurrentProfile(payload, otaUrl, otaSha256);
566596

567597
if (version.isEmpty()) {
568598
setError("manifest missing version");

tools/generate_release_manifest.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,58 @@ def main() -> int:
3030
parser.add_argument("--tag", required=True, help="Git tag, for example v0.1.5")
3131
parser.add_argument("--repository", required=True, help="GitHub repository, for example jjtronics/SoundPanel7")
3232
parser.add_argument("--published-at", required=True, help="Release publication timestamp")
33-
parser.add_argument("--build-dir", required=True, help="Directory containing firmware artifacts")
33+
parser.add_argument("--build-dir", required=True, help="Directory containing screen firmware artifacts")
34+
parser.add_argument("--headless-build-dir", required=True, help="Directory containing headless firmware artifacts")
3435
parser.add_argument("--output", required=True, help="Output manifest path")
3536
args = parser.parse_args()
3637

3738
build_dir = Path(args.build_dir)
39+
headless_build_dir = Path(args.headless_build_dir)
3840
output = Path(args.output)
3941
version = args.tag[1:] if args.tag.startswith("v") else args.tag
4042

4143
firmware = build_asset(
4244
args.repository,
4345
args.tag,
44-
"firmware.bin",
46+
"soundpanel7_ota-firmware.bin",
4547
"firmware",
4648
build_dir / "firmware.bin",
4749
)
50+
firmware_headless = build_asset(
51+
args.repository,
52+
args.tag,
53+
"soundpanel7_headless_ota-firmware.bin",
54+
"firmware",
55+
headless_build_dir / "firmware.bin",
56+
)
4857
bootloader = build_asset(
4958
args.repository,
5059
args.tag,
51-
"bootloader.bin",
60+
"soundpanel7_ota-bootloader.bin",
5261
"bootloader",
5362
build_dir / "bootloader.bin",
5463
)
64+
bootloader_headless = build_asset(
65+
args.repository,
66+
args.tag,
67+
"soundpanel7_headless_ota-bootloader.bin",
68+
"bootloader",
69+
headless_build_dir / "bootloader.bin",
70+
)
5571
partitions = build_asset(
5672
args.repository,
5773
args.tag,
58-
"partitions.bin",
74+
"soundpanel7_ota-partitions.bin",
5975
"partitions",
6076
build_dir / "partitions.bin",
6177
)
78+
partitions_headless = build_asset(
79+
args.repository,
80+
args.tag,
81+
"soundpanel7_headless_ota-partitions.bin",
82+
"partitions",
83+
headless_build_dir / "partitions.bin",
84+
)
6285

6386
manifest = {
6487
"project": "SoundPanel7",
@@ -67,7 +90,20 @@ def main() -> int:
6790
"published_at": args.published_at,
6891
"release_url": f"https://github.com/{args.repository}/releases/tag/{args.tag}",
6992
"ota": firmware,
70-
"assets": [firmware, bootloader, partitions],
93+
"ota_screen": firmware,
94+
"ota_headless": firmware_headless,
95+
"otaScreenUrl": firmware["url"],
96+
"otaScreenSha256": firmware["sha256"],
97+
"otaHeadlessUrl": firmware_headless["url"],
98+
"otaHeadlessSha256": firmware_headless["sha256"],
99+
"assets": [
100+
firmware,
101+
bootloader,
102+
partitions,
103+
firmware_headless,
104+
bootloader_headless,
105+
partitions_headless,
106+
],
71107
}
72108

73109
output.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")

0 commit comments

Comments
 (0)