From 730eb37dbd28e85927eb49e6d24341aac9d7af3e Mon Sep 17 00:00:00 2001 From: agessaman Date: Tue, 23 Jun 2026 12:55:07 -0700 Subject: [PATCH] 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. --- .../workflows/build-observer-firmwares.yml | 52 ++++- MQTT_IMPLEMENTATION.md | 2 +- build.sh | 17 +- examples/simple_repeater/MyMesh.cpp | 2 +- src/helpers/CommonCLI.cpp | 13 +- src/helpers/ESP32Board.cpp | 182 ++++++++++-------- src/helpers/MQTTPresets.h | 2 +- variants/heltec_t190/platformio.ini | 4 +- variants/heltec_v3/platformio.ini | 8 +- variants/heltec_v4/platformio.ini | 8 +- variants/lilygo_t3s3/platformio.ini | 4 +- variants/lilygo_tbeam_1w/platformio.ini | 4 +- variants/lilygo_tbeam_SX1262/platformio.ini | 4 +- variants/lilygo_tbeam_SX1276/platformio.ini | 4 +- .../platformio.ini | 4 +- variants/lilygo_tlora_v2_1/platformio.ini | 4 +- variants/rak3112/platformio.ini | 4 +- variants/station_g2/platformio.ini | 4 +- variants/xiao_s3_wio/platformio.ini | 4 +- 19 files changed, 203 insertions(+), 123 deletions(-) diff --git a/.github/workflows/build-observer-firmwares.yml b/.github/workflows/build-observer-firmwares.yml index 728aab14..0db674ae 100644 --- a/.github/workflows/build-observer-firmwares.yml +++ b/.github/workflows/build-observer-firmwares.yml @@ -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/.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 diff --git a/MQTT_IMPLEMENTATION.md b/MQTT_IMPLEMENTATION.md index 910da6b1..d218eef9 100644 --- a/MQTT_IMPLEMENTATION.md +++ b/MQTT_IMPLEMENTATION.md @@ -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) | — | — | diff --git a/build.sh b/build.sh index edcabbf0..3f58d2a0 100755 --- a/build.sh +++ b/build.sh @@ -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 -v-.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 + # (/.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 diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 72363588..d283acbd 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -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 diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index e44269c0..367ee47c 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -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 diff --git a/src/helpers/ESP32Board.cpp b/src/helpers/ESP32Board.cpp index 139b5f78..e1267a6f 100644 --- a/src/helpers/ESP32Board.cpp +++ b/src/helpers/ESP32Board.cpp @@ -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 ---------------------------------- + // /.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()) { - for (JsonObject fw : dev["firmware"].as()) { - const char* notice = fw["notice"].is() ? fw["notice"].as() : nullptr; - for (JsonPair vp : fw["version"].as()) { - for (JsonObject file : vp.value()["files"].as()) { - 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-"). + 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[]) { diff --git a/src/helpers/MQTTPresets.h b/src/helpers/MQTTPresets.h index 36ddba1a..d6726003 100644 --- a/src/helpers/MQTTPresets.h +++ b/src/helpers/MQTTPresets.h @@ -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 diff --git a/variants/heltec_t190/platformio.ini b/variants/heltec_t190/platformio.ini index 71b56556..5a9e8db2 100644 --- a/variants/heltec_t190/platformio.ini +++ b/variants/heltec_t190/platformio.ini @@ -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 diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index a71cb90f..4bd3819a 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -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 diff --git a/variants/heltec_v4/platformio.ini b/variants/heltec_v4/platformio.ini index 157ece5d..f3622bc5 100644 --- a/variants/heltec_v4/platformio.ini +++ b/variants/heltec_v4/platformio.ini @@ -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 diff --git a/variants/lilygo_t3s3/platformio.ini b/variants/lilygo_t3s3/platformio.ini index f862a9f6..4a259ee7 100644 --- a/variants/lilygo_t3s3/platformio.ini +++ b/variants/lilygo_t3s3/platformio.ini @@ -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 diff --git a/variants/lilygo_tbeam_1w/platformio.ini b/variants/lilygo_tbeam_1w/platformio.ini index 73723c29..827cac38 100644 --- a/variants/lilygo_tbeam_1w/platformio.ini +++ b/variants/lilygo_tbeam_1w/platformio.ini @@ -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 diff --git a/variants/lilygo_tbeam_SX1262/platformio.ini b/variants/lilygo_tbeam_SX1262/platformio.ini index 57517857..2e0d8334 100644 --- a/variants/lilygo_tbeam_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_SX1262/platformio.ini @@ -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 diff --git a/variants/lilygo_tbeam_SX1276/platformio.ini b/variants/lilygo_tbeam_SX1276/platformio.ini index aa3383db..41f56115 100644 --- a/variants/lilygo_tbeam_SX1276/platformio.ini +++ b/variants/lilygo_tbeam_SX1276/platformio.ini @@ -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 diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index a8a84721..7c588e7c 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -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 diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index 9a4a8365..37a909f8 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -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 diff --git a/variants/rak3112/platformio.ini b/variants/rak3112/platformio.ini index f284a3a1..130b8344 100644 --- a/variants/rak3112/platformio.ini +++ b/variants/rak3112/platformio.ini @@ -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 diff --git a/variants/station_g2/platformio.ini b/variants/station_g2/platformio.ini index aaa74b15..338f4c31 100644 --- a/variants/station_g2/platformio.ini +++ b/variants/station_g2/platformio.ini @@ -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 diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index 873454c0..8e4314cf 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -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