mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-22 20:01:17 +00:00
feat(ota): implement build number suffix for firmware versioning
Enhanced the firmware versioning system by appending a build number suffix when available, allowing for better tracking of published builds. This change improves the OTA update process by providing clearer versioning information in the embedded firmware string.
This commit is contained in:
1 parent
addb637b63
commit
730eb37dbd
19 files changed
+203
-123
No files matched your search
@@ -47,6 +47,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.split.outputs.matrix }}
|
||||
build_number: ${{ steps.buildnum.outputs.n }}
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@v4
|
||||
@@ -66,6 +67,27 @@ jobs:
|
||||
| jq -cs .)
|
||||
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compute observer build number
|
||||
id: buildnum
|
||||
shell: bash
|
||||
run: |
|
||||
# Per-base published-build counter. N increments once per release and
|
||||
# resets to 1 when FIRMWARE_VERSION (the MeshCore base version) changes.
|
||||
# Read-only here (off the published counter); the release job is the sole
|
||||
# writer and only writes on a successful build, so a failed build doesn't
|
||||
# burn a number. First run / 404 -> empty -> N=1.
|
||||
COUNTER_URL="https://observer.gessaman.com/observer-build-counter.json"
|
||||
CUR=$(curl -fsSL "$COUNTER_URL" 2>/dev/null || echo '{}')
|
||||
PREV_BASE=$(echo "$CUR" | jq -r '.baseVersion // ""')
|
||||
PREV_BUILD=$(echo "$CUR" | jq -r '.build // 0')
|
||||
if [ "$PREV_BASE" = "$FIRMWARE_VERSION" ]; then
|
||||
N=$((PREV_BUILD + 1))
|
||||
else
|
||||
N=1
|
||||
fi
|
||||
echo "Base $FIRMWARE_VERSION; previous build $PREV_BUILD (base $PREV_BASE) -> N=$N"
|
||||
echo "n=$N" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Build one shard (several envs) per runner. build.sh emits both the app
|
||||
# .bin and the ESP32 -merged.bin into out/ for each env.
|
||||
build:
|
||||
@@ -100,6 +122,9 @@ jobs:
|
||||
uses: ./.github/actions/setup-build-environment
|
||||
|
||||
- name: Build Shard ${{ matrix.shard.idx }}
|
||||
env:
|
||||
# Stamp the per-base build number into the embedded version (v1.16.0.N).
|
||||
FIRMWARE_BUILD_NUMBER: ${{ needs.enumerate.outputs.build_number }}
|
||||
run: /usr/bin/env bash build.sh build-firmware ${{ matrix.shard.envs }}
|
||||
|
||||
- name: Upload Shard Artifact
|
||||
@@ -112,7 +137,7 @@ jobs:
|
||||
# Collect all shard outputs, publish the rolling release, then point the
|
||||
# flasher at the new build by bumping the hash + notes in its config.json.
|
||||
release:
|
||||
needs: build
|
||||
needs: [enumerate, build]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
@@ -196,6 +221,23 @@ jobs:
|
||||
"${{ steps.sha.outputs.short }}" \
|
||||
"$GITHUB_WORKSPACE/firmware-notes.html"
|
||||
|
||||
- name: Generate Slim Per-Variant Manifests + Persist Build Counter
|
||||
env:
|
||||
BUILD_NUMBER: ${{ needs.enumerate.outputs.build_number }}
|
||||
run: |
|
||||
# Derive the slim per-variant manifests (flasher/v/<env>.json) that the
|
||||
# firmware fetches for `ota check`/`ota update`, from the just-updated
|
||||
# config.json (single source of truth), stamping this build's number.
|
||||
# Then persist the counter so the next run increments from here.
|
||||
python3 flasher/scripts/gen-slim-manifests.py \
|
||||
--config flasher/config.json \
|
||||
--out-dir flasher/v \
|
||||
--base-version "$FIRMWARE_VERSION" \
|
||||
--build "$BUILD_NUMBER"
|
||||
printf '{\n "baseVersion": "%s",\n "build": %s\n}\n' \
|
||||
"$FIRMWARE_VERSION" "$BUILD_NUMBER" > flasher/observer-build-counter.json
|
||||
echo "Build $FIRMWARE_VERSION.$BUILD_NUMBER"
|
||||
|
||||
- name: Unshallow for Changelog
|
||||
run: |
|
||||
# gen_changelog.py needs the full branch history; deepen only now, AFTER
|
||||
@@ -233,11 +275,15 @@ jobs:
|
||||
- name: Commit & Push Flasher Config
|
||||
working-directory: flasher
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
# Stage everything: update-firmware.py edits config.json in place, but the
|
||||
# slim manifests (v/*.json) and the build counter can be NEW files, which
|
||||
# `commit -am` would miss — so add -A and check the staged diff.
|
||||
git add -A
|
||||
if git diff --cached --quiet; then
|
||||
echo "No flasher changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "meshcore-bot"
|
||||
git config user.email "noreply@gessaman.com"
|
||||
git commit -am "Update observer firmware to ${{ steps.sha.outputs.short }}"
|
||||
git commit -m "Update observer firmware to ${{ steps.sha.outputs.short }} (build ${FIRMWARE_VERSION}.${{ needs.enumerate.outputs.build_number }})"
|
||||
git push
|
||||
@@ -116,7 +116,7 @@ The MQTT bridge uses a slot-based architecture with up to 6 concurrent connectio
|
||||
| `meshcore-ca-1` | mqtt1.meshcore.ca:443 | JWT (Ed25519) | WSS |
|
||||
| `meshcore-ca-2` | mqtt2.meshcore.ca:443 | JWT (Ed25519) | WSS |
|
||||
| `bostonmesh` | mqttmc01.bostonme.sh:443 | JWT (Ed25519) | WSS |
|
||||
| `flmesh.us` | mcmqtt.jntconnections.com:443 | JWT (Ed25519) | WSS |
|
||||
| `flmesh` | mcmqtt.jntconnections.com:443 | JWT (Ed25519) | WSS |
|
||||
| `inwmesh` | scope.inwmesh.org:8883 | Username/password (per slot via `mqttN.username` / `mqttN.password`) | MQTT over TLS |
|
||||
| `custom` | User-configured | Username/Password | MQTT or WSS |
|
||||
| `none` | (disabled) | — | — |
|
||||
|
||||
@@ -149,11 +149,22 @@ build_firmware() {
|
||||
case "$1" in
|
||||
*observer*) VARIANT_TAG="-observer" ;;
|
||||
esac
|
||||
EMBEDDED_VERSION_STRING="${FIRMWARE_VERSION}${VARIANT_TAG}-${COMMIT_HASH}"
|
||||
|
||||
# Observer build number: when CI provides FIRMWARE_BUILD_NUMBER (the per-base
|
||||
# published-build counter), append it as a 4th version component so the node
|
||||
# reports e.g. v1.16.0.5-observer-abcdef and `ota check` can show how many
|
||||
# builds behind it is. Local dev builds leave it unset → no 4th component.
|
||||
# The *filename* (FIRMWARE_VERSION_STRING above) is deliberately left without
|
||||
# the build number so assets stay <env>-v<base>-<hash>.bin.
|
||||
BUILD_NUMBER_SUFFIX=""
|
||||
if [ -n "$FIRMWARE_BUILD_NUMBER" ]; then
|
||||
BUILD_NUMBER_SUFFIX=".${FIRMWARE_BUILD_NUMBER}"
|
||||
fi
|
||||
EMBEDDED_VERSION_STRING="${FIRMWARE_VERSION}${BUILD_NUMBER_SUFFIX}${VARIANT_TAG}-${COMMIT_HASH}"
|
||||
|
||||
# add firmware version info to end of existing platformio build flags in environment vars.
|
||||
# OTA_VARIANT is the env name ($1) — it is exactly the asset-filename prefix used above, so the
|
||||
# observer pull-OTA can match its own build in the web-flasher manifest (config.json).
|
||||
# OTA_VARIANT is the env name ($1) — it selects this build's slim per-variant manifest
|
||||
# (<OTA_MANIFEST_BASE>/<OTA_VARIANT>.json) that the observer pull-OTA fetches.
|
||||
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${EMBEDDED_VERSION_STRING}\"' -DOTA_VARIANT='\"$1\"'"
|
||||
|
||||
# disable debug flags if requested
|
||||
|
||||
@@ -1445,7 +1445,7 @@ void MyMesh::loop() {
|
||||
MESH_DEBUG_PRINTLN("Radio params restored");
|
||||
}
|
||||
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(OTA_MANIFEST_URL)
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(OTA_MANIFEST_BASE)
|
||||
if (_ota_update_at && millisHasNowPassed(_ota_update_at)) { // deferred `ota update`
|
||||
_ota_update_at = 0; // clear timer
|
||||
// The "Beginning update..." reply has now gone out. Free the bridge for heap
|
||||
|
||||
@@ -799,18 +799,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
|
||||
// triggered by someone expecting to hand-upload a binary.
|
||||
// ota check -> report available build, do not flash
|
||||
// ota update -> download and flash, then reboot
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(OTA_MANIFEST_URL)
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(OTA_MANIFEST_BASE)
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
strcpy(reply, "ERR: WiFi not connected");
|
||||
} else if (memcmp(command, "ota check", 9) == 0) {
|
||||
// Check is synchronous so its result lands in this reply. Free the MQTT
|
||||
// bridge first: on a no-PSRAM board only ~70 KB heap is free with the
|
||||
// bridge up, and a third TLS connection (the manifest fetch) alongside the
|
||||
// two live MQTT sessions drives free heap to a few hundred bytes, which
|
||||
// truncates the read. The WiFi STA link survives end(); restore after.
|
||||
_callbacks->setBridgeState(false);
|
||||
// Check is synchronous so its result lands in this reply, and runs with the
|
||||
// MQTT bridge UP: the slim per-variant manifest is tiny, so the fetch only
|
||||
// costs a single TLS handshake (no large JSON doc) — which fits alongside
|
||||
// the live MQTT sessions even on no-PSRAM boards. No bridge bounce needed.
|
||||
_board->otaFromManifest(_callbacks->getFirmwareVer(), true, reply);
|
||||
_callbacks->setBridgeState(true);
|
||||
} else {
|
||||
// Update is DEFERRED: the flash blocks the loop and then reboots, so it
|
||||
// must run only AFTER this reply has gone out over the mesh — otherwise
|
||||
|
||||
+104
-78
@@ -95,6 +95,29 @@ static void ota_extractHash(const char* s, char* out, size_t out_sz) {
|
||||
out[n] = 0;
|
||||
}
|
||||
|
||||
// Split a version token "vMAJOR.MINOR.PATCH[.BUILD]" into its base
|
||||
// ("vMAJOR.MINOR.PATCH") and build number (BUILD, or -1 if there's no 4th
|
||||
// component). The base has exactly two dots; a third dot introduces the build.
|
||||
static void ota_parseVersion(const char* ver, char* base_out, size_t base_sz, int* build_out) {
|
||||
*build_out = -1;
|
||||
if (base_sz) base_out[0] = 0;
|
||||
if (!ver) return;
|
||||
int dots = 0, third_dot = -1;
|
||||
for (int j = 0; ver[j]; j++) {
|
||||
if (ver[j] == '.' && ++dots == 3) { third_dot = j; break; }
|
||||
}
|
||||
if (third_dot >= 0) {
|
||||
size_t n = (size_t)third_dot;
|
||||
if (n >= base_sz) n = base_sz - 1;
|
||||
memcpy(base_out, ver, n);
|
||||
base_out[n] = 0;
|
||||
*build_out = atoi(ver + third_dot + 1);
|
||||
} else {
|
||||
strncpy(base_out, ver, base_sz - 1);
|
||||
base_out[base_sz - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters handed to the worker task; lives on otaFromManifest()'s stack,
|
||||
// which stays valid because that function blocks until the worker signals done.
|
||||
struct OtaTaskArgs {
|
||||
@@ -133,7 +156,7 @@ bool ESP32Board::otaFromManifest(const char* current_ver, bool dry_run, char rep
|
||||
}
|
||||
|
||||
bool ESP32Board::otaFromManifestImpl(const char* current_ver, bool dry_run, char reply[]) {
|
||||
#if !defined(OTA_MANIFEST_URL) || !defined(OTA_VARIANT)
|
||||
#if !defined(OTA_MANIFEST_BASE) || !defined(OTA_VARIANT)
|
||||
strcpy(reply, "ERR: OTA not configured (build via build.sh)");
|
||||
return false;
|
||||
#else
|
||||
@@ -152,7 +175,14 @@ bool ESP32Board::otaFromManifestImpl(const char* current_ver, bool dry_run, char
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Fetch + filter-parse the manifest -----------------------------------
|
||||
// --- Fetch this variant's slim manifest ----------------------------------
|
||||
// <OTA_MANIFEST_BASE>/<OTA_VARIANT>.json — a ~180 byte per-variant file, NOT
|
||||
// the full config.json. Keeping the body tiny is what lets `ota check` run with
|
||||
// the MQTT bridge up on no-PSRAM boards: only the TLS handshake costs heap, with
|
||||
// no large JSON document layered on top.
|
||||
char murl[200];
|
||||
snprintf(murl, sizeof(murl), "%s/%s.json", OTA_MANIFEST_BASE, OTA_VARIANT);
|
||||
|
||||
WiFiClientSecure mclient;
|
||||
#if ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
mclient.setCACertBundle(rootca_crt_bundle_start, bundle_len);
|
||||
@@ -162,16 +192,15 @@ bool ESP32Board::otaFromManifestImpl(const char* current_ver, bool dry_run, char
|
||||
mclient.setTimeout(15000);
|
||||
|
||||
HTTPClient http;
|
||||
if (!http.begin(mclient, OTA_MANIFEST_URL)) {
|
||||
if (!http.begin(mclient, murl)) {
|
||||
strcpy(reply, "ERR: manifest connect failed");
|
||||
return false;
|
||||
}
|
||||
// Force HTTP/1.0: a CDN (e.g. Cloudflare) answers HTTP/1.1 with
|
||||
// Transfer-Encoding: chunked and no Content-Length, and the raw chunked
|
||||
// stream can't be fed to the JSON parser (chunk-size frames corrupt it).
|
||||
// HTTP/1.0 yields a Connection: close, unframed body we can stream-parse.
|
||||
// Force HTTP/1.0: a CDN (e.g. Cloudflare) answers HTTP/1.1 with chunked encoding
|
||||
// and no Content-Length; the raw chunked stream corrupts the parse. HTTP/1.0
|
||||
// yields a Connection: close, unframed body.
|
||||
http.useHTTP10(true);
|
||||
http.setTimeout(20000); // per-read timeout while streaming the body
|
||||
http.setTimeout(20000);
|
||||
int code = http.GET();
|
||||
if (code != HTTP_CODE_OK) {
|
||||
snprintf(reply, 160, "ERR: manifest HTTP %d", code);
|
||||
@@ -179,99 +208,96 @@ bool ESP32Board::otaFromManifestImpl(const char* current_ver, bool dry_run, char
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stream-parse straight from the network: the filter discards all but
|
||||
// staticPath + each firmware entry's notice/version, so peak RAM is just the
|
||||
// small kept subset (not the ~40 KB manifest). This matters for `ota check`,
|
||||
// which runs with the MQTT bridge still up and holding heap. (The dynamic
|
||||
// version key forces keeping its whole subtree, incl. release notes.)
|
||||
// readBytes() honours the stream timeout, so a slow TLS link won't be
|
||||
// mistaken for end-of-input.
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
stream->setTimeout(20000);
|
||||
|
||||
JsonDocument filter;
|
||||
filter["staticPath"] = true;
|
||||
filter["device"][0]["firmware"][0]["notice"] = true;
|
||||
filter["device"][0]["firmware"][0]["version"] = true;
|
||||
stream->setTimeout(20000); // readBytes honours this, so a slow TLS link != EOF
|
||||
|
||||
JsonDocument doc;
|
||||
DeserializationError err =
|
||||
deserializeJson(doc, *stream, DeserializationOption::Filter(filter));
|
||||
DeserializationError err = deserializeJson(doc, *stream);
|
||||
http.end();
|
||||
if (err) {
|
||||
snprintf(reply, 160, "ERR: manifest parse (%s)", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy out of the document up front: doc gets cleared before these are used.
|
||||
char base_url[128] = {0};
|
||||
strncpy(base_url, doc["staticPath"] | "", sizeof(base_url) - 1);
|
||||
if (!base_url[0]) {
|
||||
strcpy(reply, "ERR: manifest missing staticPath");
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Locate the flash-update build for our variant -----------------------
|
||||
const char* variant = OTA_VARIANT;
|
||||
size_t vlen = strlen(variant);
|
||||
char target_name[128] = {0};
|
||||
bool partition_change = false;
|
||||
bool found = false;
|
||||
|
||||
for (JsonObject dev : doc["device"].as<JsonArray>()) {
|
||||
for (JsonObject fw : dev["firmware"].as<JsonArray>()) {
|
||||
const char* notice = fw["notice"].is<const char*>() ? fw["notice"].as<const char*>() : nullptr;
|
||||
for (JsonPair vp : fw["version"].as<JsonObject>()) {
|
||||
for (JsonObject file : vp.value()["files"].as<JsonArray>()) {
|
||||
const char* type = file["type"] | "";
|
||||
const char* name = file["name"] | "";
|
||||
if (strcmp(type, "flash-update") != 0) continue;
|
||||
if (strncmp(name, variant, vlen) != 0 || name[vlen] != '-') continue;
|
||||
strncpy(target_name, name, sizeof(target_name) - 1);
|
||||
partition_change = (notice != nullptr && strcmp(notice, "partition-change") == 0);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
// Copy fields out before the document is reused/cleared.
|
||||
char file_url[200] = {0}, avail_version[40] = {0}, avail_base[40] = {0}, avail_hash[24] = {0};
|
||||
strncpy(file_url, doc["file"] | "", sizeof(file_url) - 1);
|
||||
strncpy(avail_version, doc["version"] | "", sizeof(avail_version) - 1);
|
||||
strncpy(avail_base, doc["baseVersion"] | "", sizeof(avail_base) - 1);
|
||||
strncpy(avail_hash, doc["hash"] | "", sizeof(avail_hash) - 1);
|
||||
int avail_build = doc["build"] | -1;
|
||||
bool partition_change = doc["partitionChange"] | false;
|
||||
doc.clear();
|
||||
|
||||
if (!found) {
|
||||
snprintf(reply, 160, "ERR: no build for %s in manifest", variant);
|
||||
if (!file_url[0]) {
|
||||
strcpy(reply, "ERR: manifest missing file");
|
||||
return false;
|
||||
}
|
||||
|
||||
char avail_hash[24], cur_hash[24];
|
||||
ota_extractHash(target_name, avail_hash, sizeof(avail_hash));
|
||||
ota_extractHash(current_ver, cur_hash, sizeof(cur_hash));
|
||||
// Compare by shared prefix: git abbreviates the same commit to 7 chars on a
|
||||
// shallow CI clone but 8 locally, so an exact match would miss equal builds.
|
||||
size_t la = strlen(avail_hash), lc = strlen(cur_hash);
|
||||
size_t m = (la < lc) ? la : lc;
|
||||
bool up_to_date = (m >= 7 && strncmp(avail_hash, cur_hash, m) == 0);
|
||||
// --- Determine current-vs-available --------------------------------------
|
||||
// Our running version token (e.g. "v1.16.0.5"), i.e. current_ver up to the
|
||||
// first '-' (which precedes "-observer-<hash>").
|
||||
char own_version[40] = {0};
|
||||
for (size_t i = 0; current_ver && current_ver[i] && current_ver[i] != '-' && i < sizeof(own_version) - 1; i++) {
|
||||
own_version[i] = current_ver[i];
|
||||
}
|
||||
char own_base[40];
|
||||
int own_build;
|
||||
ota_parseVersion(own_version, own_base, sizeof(own_base), &own_build);
|
||||
|
||||
// Fallback identity by commit hash (handles pre-build-number / local images that
|
||||
// carry no 4th version component). Shared-prefix compare absorbs the 7- vs 8-char
|
||||
// git abbreviation difference.
|
||||
char cur_hash[24];
|
||||
ota_extractHash(current_ver, cur_hash, sizeof(cur_hash));
|
||||
size_t lh = strlen(avail_hash), lc = strlen(cur_hash);
|
||||
size_t m = (lh < lc) ? lh : lc;
|
||||
bool hash_equal = (m >= 7 && strncmp(avail_hash, cur_hash, m) == 0);
|
||||
|
||||
bool same_base = (own_base[0] && avail_base[0] && strcmp(own_base, avail_base) == 0);
|
||||
bool have_builds = (own_build >= 0 && avail_build >= 0);
|
||||
bool diff_base = (own_base[0] && avail_base[0] && !same_base);
|
||||
|
||||
int behind = 0;
|
||||
bool up_to_date;
|
||||
if (same_base && have_builds) {
|
||||
behind = avail_build - own_build;
|
||||
up_to_date = (behind <= 0);
|
||||
} else if (diff_base) {
|
||||
up_to_date = false; // different base version is always an update
|
||||
} else {
|
||||
up_to_date = hash_equal; // unknown build numbers -> fall back to hash
|
||||
}
|
||||
|
||||
const char* avail_disp = avail_version[0] ? avail_version : avail_hash;
|
||||
const char* own_disp = own_version[0] ? own_version : cur_hash;
|
||||
const char* pc_note = partition_change ? " [partition change: cable flash]" : "";
|
||||
|
||||
// --- Report (dry run / `ota check`) --------------------------------------
|
||||
if (dry_run) {
|
||||
snprintf(reply, 160, "%s: %s -> %s%s", up_to_date ? "up to date" : "update available",
|
||||
cur_hash, avail_hash, partition_change ? " [partition change: cable flash]" : "");
|
||||
if (up_to_date) {
|
||||
snprintf(reply, 160, "up to date: %s", avail_disp);
|
||||
} else if (same_base && have_builds) {
|
||||
snprintf(reply, 160, "update available: %s -> %s (%d behind)%s", own_disp, avail_disp, behind, pc_note);
|
||||
} else if (diff_base) {
|
||||
snprintf(reply, 160, "update available: %s -> %s (new base)%s", own_disp, avail_disp, pc_note);
|
||||
} else {
|
||||
snprintf(reply, 160, "update available: %s -> %s%s", own_disp, avail_disp, pc_note);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Gates (real `ota update`) -------------------------------------------
|
||||
if (partition_change) {
|
||||
snprintf(reply, 160, "ERR: %s needs cable flash (partition change)", avail_hash);
|
||||
snprintf(reply, 160, "ERR: %s needs cable flash (partition change)", avail_disp);
|
||||
return false;
|
||||
}
|
||||
if (up_to_date) {
|
||||
snprintf(reply, 160, "OK: already up to date (%s)", cur_hash);
|
||||
snprintf(reply, 160, "OK: already up to date (%s)", avail_disp);
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Stream the .bin into the inactive OTA slot --------------------------
|
||||
char url[256];
|
||||
snprintf(url, sizeof(url), "%s/%s", base_url, target_name);
|
||||
|
||||
// --- Stream the .bin (the manifest's full URL) into the inactive OTA slot -
|
||||
inhibit_sleep = true; // keep awake through the flash
|
||||
|
||||
WiFiClientSecure uclient;
|
||||
@@ -283,14 +309,14 @@ bool ESP32Board::otaFromManifestImpl(const char* current_ver, bool dry_run, char
|
||||
uclient.setTimeout(20000);
|
||||
|
||||
httpUpdate.rebootOnUpdate(true); // reboots into the new image on success
|
||||
t_httpUpdate_return ret = httpUpdate.update(uclient, url);
|
||||
t_httpUpdate_return ret = httpUpdate.update(uclient, file_url);
|
||||
|
||||
// Only reached on failure (success reboots inside update()).
|
||||
inhibit_sleep = false;
|
||||
snprintf(reply, 160, "ERR: OTA failed (%d): %s", (int)ret,
|
||||
httpUpdate.getLastErrorString().c_str());
|
||||
return false;
|
||||
#endif // OTA_MANIFEST_URL && OTA_VARIANT
|
||||
#endif // OTA_MANIFEST_BASE && OTA_VARIANT
|
||||
}
|
||||
#else
|
||||
bool ESP32Board::otaFromManifest(const char* current_ver, bool dry_run, char reply[]) {
|
||||
|
||||
@@ -132,7 +132,7 @@ static const MQTTPresetDef MQTT_PRESETS[MQTT_PRESET_COUNT] = {
|
||||
{ "meshcore-fi", "wss://mc-mqtt.meshcore.fi:443/", "mc-mqtt.meshcore.fi", ISRG_ROOT_X1, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "inwmesh", "mqtts://scope.inwmesh.org:8883", nullptr, ISRG_ROOT_X1, MQTT_AUTH_USERPASS, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "bostonmesh", "wss://mqttmc01.bostonme.sh:443/mqtt", "mqttmc01.bostonme.sh", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "flmesh.us", "wss://mcmqtt.jntconnections.com:443", "mcmqtt.jntconnections.com", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "flmesh", "wss://mcmqtt.jntconnections.com:443", "mcmqtt.jntconnections.com", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
};
|
||||
|
||||
// Find a preset by name, returns nullptr if not found
|
||||
|
||||
@@ -112,7 +112,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -205,7 +205,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -123,7 +123,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -193,7 +193,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -482,7 +482,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -531,7 +531,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -162,7 +162,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -214,7 +214,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -317,7 +317,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -357,7 +357,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -116,7 +116,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
; -D MQTT_DEBUG=1
|
||||
@@ -162,7 +162,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -209,7 +209,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D PERSISTANT_GPS=1
|
||||
@@ -256,7 +256,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D PERSISTANT_GPS=1
|
||||
|
||||
@@ -161,7 +161,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
; -D MQTT_DEBUG=1
|
||||
@@ -204,7 +204,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -160,7 +160,7 @@ build_flags =
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D PERSISTANT_GPS=1
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
; -D MQTT_DEBUG=1
|
||||
@@ -203,7 +203,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -120,7 +120,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -163,7 +163,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -157,7 +157,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_TASK_STACK_SIZE=16384
|
||||
@@ -203,7 +203,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_TASK_STACK_SIZE=16384
|
||||
|
||||
@@ -113,7 +113,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -177,7 +177,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -187,7 +187,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -306,7 +306,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
@@ -103,7 +103,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
@@ -147,7 +147,7 @@ build_flags =
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D OTA_MANIFEST_URL='"https://observer.gessaman.com/config.json"'
|
||||
-D OTA_MANIFEST_BASE='"https://observer.gessaman.com/v"'
|
||||
-D MAX_MQTT_BROKERS=3
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
|
||||
Reference in new issue
Block a user