From 8a437415894db7c186a90cdd0b149cbd8c2dc9ee Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 2 Dec 2025 05:48:19 -0600 Subject: [PATCH 01/31] Add 'cleanup' to required PR labels (#8835) --- .github/workflows/pr_enforce_labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_enforce_labels.yml b/.github/workflows/pr_enforce_labels.yml index 543e23558..d60c9c8ca 100644 --- a/.github/workflows/pr_enforce_labels.yml +++ b/.github/workflows/pr_enforce_labels.yml @@ -17,7 +17,7 @@ jobs: with: script: | const labels = context.payload.pull_request.labels.map(label => label.name); - const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk']; + const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk', 'cleanup']; const hasRequiredLabel = labels.some(label => requiredLabels.includes(label)); if (!hasRequiredLabel) { core.setFailed(`PR must have at least one of the following labels before it can be merged: ${requiredLabels.join(', ')}.`); From 90584359e49e37c99b6132d95a0d5f87030c45a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 05:48:36 -0600 Subject: [PATCH 02/31] Upgrade trunk (#8836) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 342d9d4a2..d8fad73c6 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,7 +9,7 @@ plugins: lint: enabled: - checkov@3.2.495 - - renovate@42.27.1 + - renovate@42.29.4 - prettier@3.7.3 - trufflehog@3.91.1 - yamllint@1.37.1 From 0828c445fba9d7d287809bb3c52eac523a9e54fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:39:31 -0600 Subject: [PATCH 03/31] Update actions/stale action to v10.1.1 (#8848) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/stale_bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 11ba59386..fc0702bd8 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Stale PR+Issues - uses: actions/stale@v10.1.0 + uses: actions/stale@v10.1.1 with: days-before-stale: 45 stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days. From 1b4925bd07b52d3085c56b88831f9d9068fc1b37 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:50:50 -0600 Subject: [PATCH 04/31] Upgrade trunk (#8849) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index d8fad73c6..95e5b0dd2 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,9 +9,9 @@ plugins: lint: enabled: - checkov@3.2.495 - - renovate@42.29.4 - - prettier@3.7.3 - - trufflehog@3.91.1 + - renovate@42.30.4 + - prettier@3.7.4 + - trufflehog@3.91.2 - yamllint@1.37.1 - bandit@1.9.2 - trivy@0.67.2 From 3f4091622387ee64a08d0cce6ff5c393e713dda1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:30:09 -0600 Subject: [PATCH 05/31] Update alpine Docker tag to v3.23 (#8853) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- alpine.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alpine.Dockerfile b/alpine.Dockerfile index bdee57d79..b3b384101 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -28,7 +28,7 @@ RUN bash ./bin/build-native.sh "$PIO_ENV" && \ # ##### PRODUCTION BUILD ############# -FROM alpine:3.22 +FROM alpine:3.23 LABEL org.opencontainers.image.title="Meshtastic" \ org.opencontainers.image.description="Alpine Meshtastic daemon" \ org.opencontainers.image.url="https://meshtastic.org" \ From 6e9fd189b457434f6bbba9ba21469e58a9f429c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:33:19 -0600 Subject: [PATCH 06/31] Update meshtastic/device-ui digest to 4fb5f24 (#8862) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 5b9d965ef..f560bd8f5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -121,7 +121,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/3bf332240416c5cb8c919fac2a0ec7260eb3be75.zip + https://github.com/meshtastic/device-ui/archive/4fb5f24787caa841b58dbf623a52c4c5861d6722.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From eeaafda62a0a4cb4f050220f10577fc65af57c58 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:41:48 -0600 Subject: [PATCH 07/31] Update protobufs (#8871) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protobufs b/protobufs index 52fa252f1..4095e5989 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 52fa252f1e01be87ad2f7ab17ceef7882b2a4a93 +Subproject commit 4095e598902b4cd893dbcb62842514704d0f64e0 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 46de1dee0..0c48a7891 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -237,8 +237,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_T_ETH_ELITE = 91, /* Heltec HRI-3621 industrial probe */ meshtastic_HardwareModel_HELTEC_SENSOR_HUB = 92, - /* Reserved Fried Chicken ID for future use */ - meshtastic_HardwareModel_RESERVED_FRIED_CHICKEN = 93, + /* Muzi Works Muzi-Base device */ + meshtastic_HardwareModel_MUZI_BASE = 93, /* Heltec Magnetic Power Bank with Meshtastic compatible */ meshtastic_HardwareModel_HELTEC_MESH_POCKET = 94, /* Seeed Solar Node */ From bd4bcb94f0db9f1a7770910612610a4d9b19c2a0 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:14:24 +0100 Subject: [PATCH 08/31] tryfix eink parameters (#8898) --- variants/esp32s3/tlora_t3s3_epaper/platformio.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini index eca052f57..82bab453d 100644 --- a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini @@ -13,7 +13,10 @@ build_flags = -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk - -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted //20 + -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates //30 + -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} From c3a69a2742724da64a96f14594b1da569944006f Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Dec 2025 17:58:23 -0600 Subject: [PATCH 09/31] Fix backwards buttons on Thinknode-M1 (#8901) --- variants/nrf52840/ELECROW-ThinkNode-M1/variant.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/variants/nrf52840/ELECROW-ThinkNode-M1/variant.h b/variants/nrf52840/ELECROW-ThinkNode-M1/variant.h index 79e31c54a..e46f2356d 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M1/variant.h +++ b/variants/nrf52840/ELECROW-ThinkNode-M1/variant.h @@ -62,17 +62,11 @@ extern "C" { /* * Buttons */ -#define PIN_BUTTON2 (32 + 10) +#define PIN_BUTTON1 (32 + 10) +#define PIN_BUTTON2 (32 + 7) #define ALT_BUTTON_PIN PIN_BUTTON2 #define ALT_BUTTON_ACTIVE_LOW true #define ALT_BUTTON_ACTIVE_PULLUP true -#define PIN_BUTTON1 (32 + 7) - -// #define PIN_BUTTON1 (0 + 11) -// #define PIN_BUTTON1 (32 + 7) - -// #define BUTTON_CLICK_MS 400 -// #define BUTTON_TOUCH_MS 200 /* * Analog pins @@ -203,4 +197,4 @@ External serial flash WP25R1635FZUIL0 } #endif -#endif \ No newline at end of file +#endif From 65c418d4e14ba7414315b926fe18d8553ed129ae Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Dec 2025 18:13:59 -0600 Subject: [PATCH 10/31] Update protobuf name of FRIED_CHICKEN (#8903) --- src/platform/nrf52/architecture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 1568e1790..d4699cd8c 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -109,7 +109,7 @@ #elif defined(HELTEC_MESH_SOLAR) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR #elif defined(MUZI_BASE) -#define HW_VENDOR meshtastic_HardwareModel_RESERVED_FRIED_CHICKEN +#define HW_VENDOR meshtastic_HardwareModel_MUZI_BASE #else #define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN #endif From 928739e0fb8d1749d780a6d5a70aa241bb61bf1f Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 8 Dec 2025 20:31:28 -0500 Subject: [PATCH 11/31] Renovate: fix malformed comment for wollewald/BH1750_WE (#8767) --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index f560bd8f5..bf828b813 100644 --- a/platformio.ini +++ b/platformio.ini @@ -182,8 +182,8 @@ lib_deps = dfrobot/DFRobot_BMM150@1.0.0 # renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561 adafruit/Adafruit TSL2561@1.1.2 - # renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/BH1750_WE@^1.1.10 - wollewald/BH1750_WE@^1.1.10 + # renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE + wollewald/BH1750_WE@1.1.10 ; (not included in native / portduino) [environmental_extra] From 042543eb25fd66410e942430c6eab0519adf61d0 Mon Sep 17 00:00:00 2001 From: Lewis He Date: Tue, 9 Dec 2025 19:39:27 +0800 Subject: [PATCH 12/31] Fixed the issue where T-Echo did not completely shut down peripherals upon power-off. (#8524) Co-authored-by: Ben Meadors --- src/platform/nrf52/main-nrf52.cpp | 10 ++++++++++ variants/nrf52840/t-echo/variant.h | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index c03cc4454..5d1ba20ba 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -335,6 +335,16 @@ void cpuDeepSleep(uint32_t msecToWake) if (Serial1) // A straightforward solution to the wake from deepsleep problem Serial1.end(); #endif + +#ifdef TTGO_T_ECHO + // To power off the T-Echo, the display must be set + // as an input pin; otherwise, there will be leakage current. + pinMode(PIN_EINK_CS, INPUT); + pinMode(PIN_EINK_DC, INPUT); + pinMode(PIN_EINK_RES, INPUT); + pinMode(PIN_EINK_BUSY, INPUT); +#endif + setBluetoothEnable(false); #ifdef RAK4630 diff --git a/variants/nrf52840/t-echo/variant.h b/variants/nrf52840/t-echo/variant.h index 4f3a53ebf..37d3368c3 100644 --- a/variants/nrf52840/t-echo/variant.h +++ b/variants/nrf52840/t-echo/variant.h @@ -181,7 +181,7 @@ External serial flash WP25R1635FZUIL0 #define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake // Seems to be missing on this new board -// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +#define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS #define GPS_TX_PIN (32 + 9) // This is for bits going TOWARDS the CPU #define GPS_RX_PIN (32 + 8) // This is for bits going TOWARDS the GPS @@ -203,7 +203,6 @@ External serial flash WP25R1635FZUIL0 #define PIN_SPI_MOSI (0 + 22) #define PIN_SPI_SCK (0 + 19) -#define PIN_PWR_EN (0 + 6) // To debug via the segger JLINK console rather than the CDC-ACM serial device // #define USE_SEGGER From 6b11991be048cff335044cccaaae21e22b52c1ac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 06:03:52 -0600 Subject: [PATCH 13/31] Upgrade trunk (#8856) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 95e5b0dd2..80851e6d5 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,24 +9,24 @@ plugins: lint: enabled: - checkov@3.2.495 - - renovate@42.30.4 + - renovate@42.40.3 - prettier@3.7.4 - trufflehog@3.91.2 - yamllint@1.37.1 - bandit@1.9.2 - - trivy@0.67.2 + - trivy@0.68.1 - taplo@0.10.0 - - ruff@0.14.7 + - ruff@0.14.8 - isort@7.0.0 - markdownlint@0.46.0 - - oxipng@9.1.5 + - oxipng@10.0.0 - svgo@4.0.0 - actionlint@1.7.9 - flake8@7.3.0 - hadolint@2.14.0 - shfmt@3.6.0 - shellcheck@0.11.0 - - black@25.11.0 + - black@25.12.0 - git-diff-check - gitleaks@8.30.0 - clang-format@16.0.3 From 69b9977fc11e13135ec7f5559bbb4f7139e9a3b8 Mon Sep 17 00:00:00 2001 From: Austin Lane Date: Tue, 9 Dec 2025 07:48:30 -0500 Subject: [PATCH 14/31] Fix apply device-install permissions device-install.sh doesn't exist for non-esp32 targets --- .github/workflows/build_one_target.yml | 4 ++-- .github/workflows/main_matrix.yml | 8 ++++---- .github/workflows/merge_queue.yml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml index 02aad5a9c..9d9e0114b 100644 --- a/.github/workflows/build_one_target.yml +++ b/.github/workflows/build_one_target.yml @@ -139,8 +139,8 @@ jobs: - name: Device scripts permissions run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh + chmod +x ./output/device-install.sh || true + chmod +x ./output/device-update.sh || true - name: Zip firmware run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index b4f4c3d11..f48a7ebd0 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -207,8 +207,8 @@ jobs: - name: Device scripts permissions run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh + chmod +x ./output/device-install.sh || true + chmod +x ./output/device-update.sh || true - name: Zip firmware run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output @@ -338,8 +338,8 @@ jobs: - name: Device scripts permissions run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh + chmod +x ./output/device-install.sh || true + chmod +x ./output/device-update.sh || true - name: Zip firmware run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output diff --git a/.github/workflows/merge_queue.yml b/.github/workflows/merge_queue.yml index b9bb3ceed..a71afad9d 100644 --- a/.github/workflows/merge_queue.yml +++ b/.github/workflows/merge_queue.yml @@ -188,8 +188,8 @@ jobs: - name: Device scripts permissions run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh + chmod +x ./output/device-install.sh || true + chmod +x ./output/device-update.sh || true - name: Zip firmware run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output @@ -303,8 +303,8 @@ jobs: - name: Device scripts permissions run: | - chmod +x ./output/device-install.sh - chmod +x ./output/device-update.sh + chmod +x ./output/device-install.sh || true + chmod +x ./output/device-update.sh || true - name: Zip firmware run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output From e691bd97324cd01960b783721218a7db4e1dff44 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Dec 2025 08:02:04 -0600 Subject: [PATCH 15/31] Revert "Cut NRF52 bluetooth power usage by 300% - testers needed! (#8858)" This reverts commit ae8d3fbb3d4fb45a0162bc70b6f8ccb37fc677c0. --- src/platform/nrf52/NRF52Bluetooth.cpp | 34 ++----------------- .../nrf52840/heltec_mesh_node_t114/variant.h | 4 +-- variants/nrf52840/tracker-t1000-e/variant.h | 4 +-- 3 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index f1bc43312..4f7fb4776 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -64,16 +64,6 @@ void onConnect(uint16_t conn_handle) connection->getPeerName(central_name, sizeof(central_name)); LOG_INFO("BLE Connected to %s", central_name); - // negotiate connections params as soon as possible - - ble_gap_conn_params_t newParams; - newParams.min_conn_interval = 24; - newParams.max_conn_interval = 40; - newParams.slave_latency = 5; - newParams.conn_sup_timeout = 400; - - sd_ble_gap_conn_param_update(conn_handle, &newParams); - // Notify UI (or any other interested firmware components) meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED); bluetoothStatus->updateStatus(&newStatus); @@ -129,7 +119,7 @@ void startAdv(void) Bluefruit.Advertising.addService(meshBleService); /* Start Advertising * - Enable auto advertising if disconnected - * - Interval: fast mode = 20 ms, slow mode = 417,5 ms + * - Interval: fast mode = 20 ms, slow mode = 152.5 ms * - Timeout for fast mode is 30 seconds * - Start(timeout) with timeout = 0 will advertise forever (until connected) * @@ -137,7 +127,7 @@ void startAdv(void) * https://developer.apple.com/library/content/qa/qa1931/_index.html */ Bluefruit.Advertising.restartOnDisconnect(true); - Bluefruit.Advertising.setInterval(32, 668); // in unit of 0.625 ms + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } @@ -282,24 +272,6 @@ void NRF52Bluetooth::setup() // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect); - - // Set slave latency to 5 to conserve power - // Despite name this does not impact data transfer - // https://docs.silabs.com/bluetooth/2.13/bluetooth-general-system-and-performance/optimizing-current-consumption-in-bluetooth-low-energy-devices - - Bluefruit.Periph.setConnSlaveLatency(5); - - // TODO: Adafruit defaul min, max interval seems to be (20,30) [in 1.25 ms units] -> (25.00, 31.25) milliseconds - // so using formula Interval Max * (Slave Latency + 1) ≤ 2 seconds - // max slave latency we can use is 30 (max available in BLE) - // and even double max inteval (see apple doc linked above for formulas) - // See Periph.SetConnInterval method - - // Tweak this later for even more power savings once those changes are confirmed to work well. - // Changing min, max interval may slow BLE transfer a bit - bumping slave latency will most likely not. - - - #ifndef BLE_DFU_SECURE bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bledfu.begin(); // Install the DFU helper @@ -328,7 +300,7 @@ void NRF52Bluetooth::setup() void NRF52Bluetooth::resumeAdvertising() { Bluefruit.Advertising.restartOnDisconnect(true); - Bluefruit.Advertising.setInterval(32, 668); // in unit of 0.625 ms + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); } diff --git a/variants/nrf52840/heltec_mesh_node_t114/variant.h b/variants/nrf52840/heltec_mesh_node_t114/variant.h index 03c5aafd2..28404fcce 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/variant.h +++ b/variants/nrf52840/heltec_mesh_node_t114/variant.h @@ -21,8 +21,8 @@ /** Master clock frequency */ #define VARIANT_MCK (64000000ul) -//#define USE_LFXO // Board uses 32khz crystal for LF -#define USE_LFRC // Board uses RC for LF +#define USE_LFXO // Board uses 32khz crystal for LF + /*---------------------------------------------------------------------------- * Headers *----------------------------------------------------------------------------*/ diff --git a/variants/nrf52840/tracker-t1000-e/variant.h b/variants/nrf52840/tracker-t1000-e/variant.h index ff63a4155..5b6719e12 100644 --- a/variants/nrf52840/tracker-t1000-e/variant.h +++ b/variants/nrf52840/tracker-t1000-e/variant.h @@ -22,9 +22,7 @@ /** Master clock frequency */ #define VARIANT_MCK (64000000ul) -//#define USE_LFXO // Board uses 32khz crystal for LF - -#define USE_LFRC +#define USE_LFXO // Board uses 32khz crystal for LF /*---------------------------------------------------------------------------- * Headers From 817f3b9ec89b43d2510fcb942386e01e7edba170 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 9 Dec 2025 10:57:02 -0500 Subject: [PATCH 16/31] Update platformio/espressif32 to v6.12.0 (#7697) --- extra_scripts/esp32_extra.py | 6 ++++++ variants/esp32/esp32.ini | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/extra_scripts/esp32_extra.py b/extra_scripts/esp32_extra.py index 8841ad1dc..f7698561a 100755 --- a/extra_scripts/esp32_extra.py +++ b/extra_scripts/esp32_extra.py @@ -10,6 +10,12 @@ Import("env") platform = env.PioPlatform() sys.path.append(join(platform.get_package_dir("tool-esptoolpy"))) +# IntelHex workaround, remove after fixed upstream +# https://github.com/platformio/platform-espressif32/issues/1632 +try: + import intelhex +except ImportError: + env.Execute("$PYTHONEXE -m pip install intelhex") import esptool diff --git a/variants/esp32/esp32.ini b/variants/esp32/esp32.ini index 5171bc45c..4bc48cebb 100644 --- a/variants/esp32/esp32.ini +++ b/variants/esp32/esp32.ini @@ -5,7 +5,7 @@ custom_esp32_kind = esp32 custom_mtjson_part = platform = # renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32 - platformio/espressif32@6.11.0 + platformio/espressif32@6.12.0 extra_scripts = ${env.extra_scripts} From d75680a2dd426fef9a66a2737d1a56acbdfdc05a Mon Sep 17 00:00:00 2001 From: Igor Danilov <59930161+polarikus@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:24:41 +0300 Subject: [PATCH 17/31] Fix #8915 [Bug]: Exception Decoder does not recognize the backtrace (#8917) --- bin/exception_decoder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/exception_decoder.py b/bin/exception_decoder.py index ec94ce20e..ffe6d3f24 100755 --- a/bin/exception_decoder.py +++ b/bin/exception_decoder.py @@ -75,7 +75,7 @@ TOOLS = { } BACKTRACE_REGEX = re.compile( - r"(?:\s+(0x40[0-2](?:\d|[a-f]|[A-F]){5}):0x(?:\d|[a-f]|[A-F]){8})\b" + r"\b(0x4[0-9a-fA-F]{7,8}):0x[0-9a-fA-F]{8}\b" ) EXCEPTION_REGEX = re.compile("^Exception \\((?P[0-9]*)\\):$") COUNTER_REGEX = re.compile( @@ -89,7 +89,7 @@ POINTER_REGEX = re.compile( STACK_BEGIN = ">>>stack>>>" STACK_END = "<<[0-9a-f]+):\W+(?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+)(\W.*)?$" + r"^(?P[0-9a-f]+):\W+(?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+)(\W.*)?$" ) StackLine = namedtuple("StackLine", ["offset", "content"]) @@ -223,7 +223,7 @@ class AddressResolver(object): if match is None: if last is not None and line.startswith("(inlined by)"): line = line[12:].strip() - self._address_map[last] += "\n \-> inlined by: " + line + self._address_map[last] += "\n \\-> inlined by: " + line continue if match.group("result") == "?? ??:0": From aa605fc4a2211974e8e9b5c22bf496f69a2b16ee Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 9 Dec 2025 15:27:13 -0500 Subject: [PATCH 18/31] Actions: Fix release manifest formating (#8918) --- .github/workflows/main_matrix.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index f48a7ebd0..acd63f28f 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -280,9 +280,9 @@ jobs: - name: Generate Release manifest run: | - jq -n --arg ver "${{ needs.version.outputs.long }}" --arg targets "${{ toJson(needs.setup.outputs.all) }}" '{ + jq -n --arg ver "${{ needs.version.outputs.long }}" --argjson targets ${{ toJson(needs.setup.outputs.all) }} '{ "version": $ver, - "targets": ($targets | fromjson) + "targets": $targets }' > firmware-${{ needs.version.outputs.long }}.json - name: Save Release manifest artifact From c55bea846094d491809c1f2c1277d351e08e5771 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 9 Dec 2025 16:11:07 -0500 Subject: [PATCH 19/31] ARCtastic (#8904) -- Do It Live! Actions Runner Controller Co-authored-by: Jonathan Bennett --- .github/actionlint.yaml | 1 + .github/workflows/build_firmware.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index f7bf95f83..f79e4fdb5 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -2,4 +2,5 @@ self-hosted-runner: # Labels of self-hosted runner in array of strings. labels: + - arctastic - test-runner diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml index c3b70d4c9..28e4ee994 100644 --- a/.github/workflows/build_firmware.yml +++ b/.github/workflows/build_firmware.yml @@ -18,7 +18,8 @@ permissions: read-all jobs: pio-build: name: build-${{ inputs.platform }} - runs-on: ubuntu-24.04 + # Use 'arctastic' self-hosted runner pool when building in the main repo + runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }} outputs: artifact-id: ${{ steps.upload.outputs.artifact-id }} steps: From ec0dfb73372238953a7a1f6bb01e850df9f4a867 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:56:27 -0600 Subject: [PATCH 20/31] Update peter-evans/create-pull-request action to v8 (#8919) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release_channels.yml | 2 +- .github/workflows/update_protobufs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml index f21b13ee1..badbb31d4 100644 --- a/.github/workflows/release_channels.yml +++ b/.github/workflows/release_channels.yml @@ -102,7 +102,7 @@ jobs: PIP_DISABLE_PIP_VERSION_CHECK: 1 - name: Create Bumps pull request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@v8 with: base: ${{ github.event.repository.default_branch }} branch: create-pull-request/bump-version diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml index af0557fda..d9ef98194 100644 --- a/.github/workflows/update_protobufs.yml +++ b/.github/workflows/update_protobufs.yml @@ -31,7 +31,7 @@ jobs: ./bin/regen-protos.sh - name: Create pull request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@v8 with: branch: create-pull-request/update-protobufs labels: submodules From aa72e397f29462001ea29c90b1c08fa3c81fa593 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 9 Dec 2025 17:40:37 -0500 Subject: [PATCH 21/31] PIO: Fix closedcube lib reference (#8920) Fixes ClosedCube reinstalling on every build --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 218b75443..25997e11d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -207,7 +207,7 @@ lib_deps = # renovate: datasource=custom.pio depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/library/SparkFun Qwiic Scale NAU7802 Arduino Library sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6 # renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001 - ClosedCube OPT3001@1.1.2 + closedcube/ClosedCube OPT3001@1.1.2 # renovate: datasource=custom.pio depName=Bosch BSEC2 packageName=boschsensortec/library/bsec2 boschsensortec/bsec2@1.10.2610 # renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library From ee80ec7b687075c60a5f1dada33906c5207fda3f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 06:14:00 -0600 Subject: [PATCH 22/31] Upgrade trunk (#8922) Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> --- .trunk/trunk.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 80851e6d5..565433c38 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,9 +9,9 @@ plugins: lint: enabled: - checkov@3.2.495 - - renovate@42.40.3 + - renovate@42.42.2 - prettier@3.7.4 - - trufflehog@3.91.2 + - trufflehog@3.92.1 - yamllint@1.37.1 - bandit@1.9.2 - trivy@0.68.1 From 5910cc2e269cac13275d198434d34be210eb3d9d Mon Sep 17 00:00:00 2001 From: Alex Samorukov Date: Wed, 10 Dec 2025 13:23:23 +0100 Subject: [PATCH 23/31] Use PSRAM to reduce heap usage percentage on ESP32 with PSRAM (#8891) * Use PSRAM for malloc > 256bytes to get more heap memory * Use dynamic allocator on boards with PSRAM to free more heap * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Move heap_caps_malloc_extmem_enable() to the top of the init * Update src/main.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Meadors Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/main.cpp | 5 +++++ src/mesh/Router.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f8d89e1ba..eb6dea327 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -439,6 +439,11 @@ void setup() LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n"); +#if defined(ARCH_ESP32) && defined(BOARD_HAS_PSRAM) + // use PSRAM for malloc calls > 256 bytes + heap_caps_malloc_extmem_enable(256); +#endif + #if defined(DEBUG_MUTE) && defined(DEBUG_PORT) DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n"); DEBUG_PORT.printf("Version %s for %s from %s\r\n", optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO)); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 05f47d7f4..54a34fd35 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -37,8 +37,8 @@ static MemoryDynamic dynamicPool; Allocator &packetPool = dynamicPool; -#elif defined(ARCH_STM32WL) -// On STM32 there isn't enough heap left over for the rest of the firmware if we allocate this statically. +#elif defined(ARCH_STM32WL) || defined(BOARD_HAS_PSRAM) +// On STM32 and boards with PSRAM, there isn't enough heap left over for the rest of the firmware if we allocate this statically. // For now, make it dynamic again. #define MAX_PACKETS \ (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \ From 2032ff1c32cf222c3d2a41d9b041f13c7fe71c6d Mon Sep 17 00:00:00 2001 From: Jason P Date: Wed, 10 Dec 2025 11:09:37 -0600 Subject: [PATCH 24/31] Create new screen colors for BaseUI (#8921) * Create new colors for BaseUI * Update Ice color --- src/graphics/draw/MenuHandler.cpp | 37 ++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index f782dabb6..2a7f479b4 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -1041,12 +1041,13 @@ void menuHandler::switchToMUIMenu() void menuHandler::TFTColorPickerMenu(OLEDDisplay *display) { - static const char *optionsArray[] = {"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Teal", - "Pink", "White"}; + static const char *optionsArray[] = { + "Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Blue", "Teal", "Cyan", "Ice", "Pink", + "White", "Gray"}; BannerOverlayOptions bannerOptions; bannerOptions.message = "Select Screen Color"; bannerOptions.optionsArrayPtr = optionsArray; - bannerOptions.optionsCount = 10; + bannerOptions.optionsCount = 14; bannerOptions.bannerCallback = [display](int selected) -> void { #if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || \ HAS_TFT || defined(HACKADAY_COMMUNICATOR) @@ -1082,20 +1083,40 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display) TFT_MESH_g = 153; TFT_MESH_b = 255; } else if (selected == 7) { - LOG_INFO("Setting color to Teal"); - TFT_MESH_r = 64; - TFT_MESH_g = 224; - TFT_MESH_b = 208; + LOG_INFO("Setting color to Blue"); + TFT_MESH_r = 0; + TFT_MESH_g = 0; + TFT_MESH_b = 255; } else if (selected == 8) { + LOG_INFO("Setting color to Teal"); + TFT_MESH_r = 16; + TFT_MESH_g = 102; + TFT_MESH_b = 102; + } else if (selected == 9) { + LOG_INFO("Setting color to Cyan"); + TFT_MESH_r = 0; + TFT_MESH_g = 255; + TFT_MESH_b = 255; + } else if (selected == 10) { + LOG_INFO("Setting color to Ice"); + TFT_MESH_r = 173; + TFT_MESH_g = 216; + TFT_MESH_b = 230; + } else if (selected == 11) { LOG_INFO("Setting color to Pink"); TFT_MESH_r = 255; TFT_MESH_g = 105; TFT_MESH_b = 180; - } else if (selected == 9) { + } else if (selected == 12) { LOG_INFO("Setting color to White"); TFT_MESH_r = 255; TFT_MESH_g = 255; TFT_MESH_b = 255; + } else if (selected == 13) { + LOG_INFO("Setting color to Gray"); + TFT_MESH_r = 128; + TFT_MESH_g = 128; + TFT_MESH_b = 128; } else { menuQueue = system_base_menu; screen->runNow(); From 83b603827c85630883e49de605967fab5de3c7fd Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 10 Dec 2025 16:29:50 -0600 Subject: [PATCH 25/31] Enable Muzi-base LED notification (#8925) --- src/mesh/NodeDB.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d3000c500..192f29553 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -805,11 +805,15 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.external_notification.output_ms = 500; moduleConfig.external_notification.nag_timeout = 2; #endif -#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) +#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) // Default to RAK led pin 2 (blue) moduleConfig.external_notification.enabled = true; moduleConfig.external_notification.output = PIN_LED2; +#if defined(MUZI_BASE) + moduleConfig.external_notification.active = false; +#else moduleConfig.external_notification.active = true; +#endif moduleConfig.external_notification.alert_message = true; moduleConfig.external_notification.output_ms = 1000; moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs; From ff0a4ea3207cba2eeb8b9b61ec1b7dc1510f3b21 Mon Sep 17 00:00:00 2001 From: Jason P Date: Wed, 10 Dec 2025 16:30:26 -0600 Subject: [PATCH 26/31] Update System Frame for improved rendering on devices (#8923) --- src/graphics/draw/DebugRenderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 1b3a148d6..ceb3b83f5 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -532,8 +532,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x const int labelX = x; int barsOffset = (isHighResolution) ? 24 : 0; #ifdef USE_EINK +#ifndef T_DECK_PRO barsOffset -= 12; #endif +#endif #if defined(M5STACK_UNITC6L) const int barX = x + 45 + barsOffset; #else @@ -574,7 +576,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x #endif // Value string display->setTextAlignment(TEXT_ALIGN_RIGHT); - display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr); + display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr); }; // === Memory values === From fba92229a67d47123d0d2c36423b9605050da0ad Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 10 Dec 2025 18:01:52 -0600 Subject: [PATCH 27/31] Add I2C device check for seesaw device on native (#8927) It turns out the logic here was attempting to access i2c without being told to do so. Not good, especially on desktops. --- src/modules/Modules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index f918d630f..63392f7e4 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -217,7 +217,7 @@ void setupModules() } #endif // HAS_BUTTON #if ARCH_PORTDUINO - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") { seesawRotary = new SeesawRotary("SeesawRotary"); if (!seesawRotary->init()) { delete seesawRotary; From fff2bbf4a0158aa499fbc6904e0d0e60d7dfbb0f Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Wed, 10 Dec 2025 17:05:26 -0800 Subject: [PATCH 28/31] Use truncated position for smart position (#8906) --- src/modules/PositionModule.cpp | 54 +++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 8b6a9f19c..776c3b5a6 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -45,8 +45,12 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes { auto p = *pptr; - // If inbound message is a replay (or spoof!) of our own messages, we shouldn't process - // (why use second-hand sources for our own data?) + const auto transport = mp.transport_mechanism; + if (isFromUs(&mp) && !IS_ONE_OF(transport, meshtastic_MeshPacket_TransportMechanism_TRANSPORT_INTERNAL, + meshtastic_MeshPacket_TransportMechanism_TRANSPORT_API)) { + LOG_WARN("Ignoring packet supposedly from us over external transport"); + return true; + } // FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER) // to set fixed location, EUD-GPS location or just the time (see also issue #900) @@ -472,19 +476,53 @@ void PositionModule::sendLostAndFoundText() delete[] message; } +// Helper: return imprecise (truncated + centered) lat/lon as int32 using current precision +static inline void computeImpreciseLatLon(int32_t inLat, int32_t inLon, uint8_t precisionBits, int32_t &outLat, int32_t &outLon) +{ + if (precisionBits > 0 && precisionBits < 32) { + // Build mask for top 'precisionBits' bits of a 32-bit unsigned field + const uint32_t mask = (precisionBits == 32) ? UINT32_MAX : (UINT32_MAX << (32 - precisionBits)); + // Note: latitude_i/longitude_i are stored as signed 32-bit in meshtastic code but + // the bitmask logic used previously operated as unsigned—preserve that behavior by + // casting to uint32_t for masking, then back to int32_t. + uint32_t lat_u = static_cast(inLat) & mask; + uint32_t lon_u = static_cast(inLon) & mask; + + // Add the "center of cell" offset used elsewhere: + // The code previously added (1 << (31 - precision)) to produce the middle of the possible location. + uint32_t center_offset = (1u << (31 - precisionBits)); + lat_u += center_offset; + lon_u += center_offset; + + outLat = static_cast(lat_u); + outLon = static_cast(lon_u); + } else { + // full precision: return input unchanged + outLat = inLat; + outLon = inLon; + } +} + struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition) { - // The minimum distance to travel before we are able to send a new position packet. const uint32_t distanceTravelThreshold = Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100); - // Determine the distance in meters between two points on the globe - float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter( - lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7); + int32_t lastLatImprecise, lastLonImprecise; + int32_t currentLatImprecise, currentLonImprecise; - return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend), + computeImpreciseLatLon(lastGpsLatitude, lastGpsLongitude, precision, lastLatImprecise, lastLonImprecise); + computeImpreciseLatLon(currentPosition.latitude_i, currentPosition.longitude_i, precision, currentLatImprecise, + currentLonImprecise); + + float distMeters = GeoCoord::latLongToMeter(lastLatImprecise * 1e-7, lastLonImprecise * 1e-7, currentLatImprecise * 1e-7, + currentLonImprecise * 1e-7); + + float distanceTraveled = fabsf(distMeters); + + return SmartPosition{.distanceTraveled = distanceTraveled, .distanceThreshold = distanceTravelThreshold, - .hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold}; + .hasTraveledOverThreshold = distanceTraveled >= distanceTravelThreshold}; } void PositionModule::handleNewPosition() From 4fc96bdf832cdc56dbf0d4a6d1b04301d50e59d5 Mon Sep 17 00:00:00 2001 From: Austin Date: Thu, 11 Dec 2025 13:26:21 -0500 Subject: [PATCH 29/31] Use 'gh-action-runner' action for "Check" jobs. (#8938) Everything's pre-baked, 503 no more! --- .github/workflows/main_matrix.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index acd63f28f..eb1ccdff0 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -77,16 +77,21 @@ jobs: fail-fast: false matrix: check: ${{ fromJson(needs.setup.outputs.check) }} - - runs-on: ubuntu-latest + # Use 'arctastic' self-hosted runner pool when checking in the main repo + runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }} if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }} steps: - uses: actions/checkout@v6 - - name: Build base - id: base - uses: ./.github/actions/setup-base + with: + submodules: recursive + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} - name: Check ${{ matrix.check.board }} - run: bin/check-all.sh ${{ matrix.check.board }} + uses: meshtastic/gh-action-firmware@main + with: + pio_platform: ${{ matrix.check.platform }} + pio_env: ${{ matrix.check.board }} + pio_target: check build: needs: [setup, version] From bcfe069997ee0002f07ed07fd6c802e2610843ef Mon Sep 17 00:00:00 2001 From: Austin Date: Thu, 11 Dec 2025 20:01:31 -0500 Subject: [PATCH 30/31] Optimize builds to reduce duplicate dependency checks (#8943) 'mtjson' will now build all required pieces when they don't exist --- bin/build-esp32.sh | 16 +++------------- bin/build-nrf52.sh | 7 ++----- bin/build-rp2xx0.sh | 7 ++----- bin/build-stm32wl.sh | 7 ++----- bin/platformio-custom.py | 20 +++++++++++--------- bin/platformio-pre.py | 3 +++ 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index 8c684aa7e..4e799b30a 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -22,7 +22,7 @@ export APP_VERSION=$VERSION basename=firmware-$1-$VERSION -pio run --environment $1 # -v +pio run --environment $1 -t mtjson # -v cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf @@ -32,20 +32,10 @@ cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin echo "Copying ESP32 update bin file" cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin -echo "Building Filesystem for ESP32 targets" -# If you want to build the webui, uncomment the following lines -# pio run --environment $1 -t buildfs -# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin -# # Remove webserver files from the filesystem and rebuild -# ls -l data/static # Diagnostic list of files -# rm -rf data/static -pio run --environment $1 -t buildfs --disable-auto-clean +echo "Copying Filesystem for ESP32 targets" cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin cp bin/device-install.* $OUTDIR/ cp bin/device-update.* $OUTDIR/ -# Generate the manifest file -echo "Generating Meshtastic manifest" -TIMEFORMAT="Generated manifest in %E seconds" -time pio run --environment $1 -t mtjson --silent --disable-auto-clean +echo "Copying manifest" cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index c605fb1e0..e3a421865 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -22,7 +22,7 @@ export APP_VERSION=$VERSION basename=firmware-$1-$VERSION -pio run --environment $1 # -v +pio run --environment $1 -t mtjson # -v cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf @@ -47,8 +47,5 @@ if (echo $1 | grep -q "rak4631"); then cp $SRCHEX $OUTDIR/ fi -# Generate the manifest file -echo "Generating Meshtastic manifest" -TIMEFORMAT="Generated manifest in %E seconds" -time pio run --environment $1 -t mtjson --silent --disable-auto-clean +echo "Copying manifest" cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json diff --git a/bin/build-rp2xx0.sh b/bin/build-rp2xx0.sh index ae26fdfbf..3ef1c1e34 100755 --- a/bin/build-rp2xx0.sh +++ b/bin/build-rp2xx0.sh @@ -22,15 +22,12 @@ export APP_VERSION=$VERSION basename=firmware-$1-$VERSION -pio run --environment $1 # -v +pio run --environment $1 -t mtjson # -v cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf echo "Copying uf2 file" cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2 -# Generate the manifest file -echo "Generating Meshtastic manifest" -TIMEFORMAT="Generated manifest in %E seconds" -time pio run --environment $1 -t mtjson --silent --disable-auto-clean +echo "Copying manifest" cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json diff --git a/bin/build-stm32wl.sh b/bin/build-stm32wl.sh index b85da04a6..023f3603c 100755 --- a/bin/build-stm32wl.sh +++ b/bin/build-stm32wl.sh @@ -22,15 +22,12 @@ export APP_VERSION=$VERSION basename=firmware-$1-$VERSION -pio run --environment $1 # -v +pio run --environment $1 -t mtjson # -v cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf echo "Copying STM32 bin file" cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin -# Generate the manifest file -echo "Generating Meshtastic manifest" -TIMEFORMAT="Generated manifest in %E seconds" -time pio run --environment $1 -t mtjson --silent --disable-auto-clean +echo "Copying manifest" cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 151cf0a97..3fdbffb70 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -159,20 +159,22 @@ def load_boot_logo(source, target, env): # Load the boot logo on TFT builds if ("HAS_TFT", 1) in env.get("CPPDEFINES", []): - env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo) + env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo) -# Rename (mv) littlefs.bin to include the PROGNAME -# This ensures the littlefs.bin is named consistently with the firmware -env.AddPostAction('$BUILD_DIR/littlefs.bin', env.VerboseAction( - f'mv $BUILD_DIR/littlefs.bin $BUILD_DIR/{lfsbin}', - f'Renaming littlefs.bin to {lfsbin}' -)) +mtjson_deps = ["buildprog"] +if platform.name == "espressif32": + # Build littlefs image as part of mtjson target + # Equivalent to `pio run -t buildfs` + target_lfs = env.DataToBin( + join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR" + ) + mtjson_deps.append(target_lfs) env.AddCustomTarget( name="mtjson", - dependencies=None, + dependencies=mtjson_deps, actions=[manifest_gather], title="Meshtastic Manifest", description="Generating Meshtastic manifest JSON + Checksums", - always_build=True, + always_build=False, ) diff --git a/bin/platformio-pre.py b/bin/platformio-pre.py index 4e51a6544..16278b813 100644 --- a/bin/platformio-pre.py +++ b/bin/platformio-pre.py @@ -11,6 +11,9 @@ else: prefsLoc = env["PROJECT_DIR"] + "/version.properties" verObj = readProps(prefsLoc) env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}") + env.Replace(ESP32_FS_IMAGE_NAME=f"littlefs-{env.get('PIOENV')}-{verObj['long']}") # Print the new program name for verification print(f"PROGNAME: {env.get('PROGNAME')}") +if platform.name == "espressif32": + print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}") From 68250dc9375ccb270b0eb5c0280fa83e0b5076d1 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:19:32 +0100 Subject: [PATCH 31/31] Mark implicit ACK for MQTT as MQTT transport (#8939) * Mark implicit ACK for MQTT as MQTT transport * TRUNK * Fix build * Make sure implicit ACKs from MQTT do not stop retransmissions in ReliableRouter --------- Co-authored-by: Ben Meadors --- src/mesh/MeshModule.h | 2 +- src/mesh/ReliableRouter.cpp | 4 +++- src/modules/RoutingModule.cpp | 6 ++++++ src/modules/RoutingModule.h | 3 +++ src/mqtt/MQTT.cpp | 9 ++++++--- src/platform/nrf52/main-nrf52.cpp | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index eda3f8881..e7178bcfe 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -225,4 +225,4 @@ class MeshModule /** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet * This ensures that if the request packet was sent reliably, the reply is sent that way as well. */ -void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to); \ No newline at end of file +void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 00066a7a3..7619fc106 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -150,7 +150,9 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records - if (ackId || nakId) { + if ((ackId || nakId) && + // Implicit ACKs from MQTT should not stop retransmissions + !(isFromUs(p) && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT)) { LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId); if (ackId) { stopRetransmission(p->to, ackId); diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index 05173983c..662f5379a 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -75,6 +75,12 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit } +meshtastic_MeshPacket *RoutingModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, + uint8_t hopLimit) +{ + return MeshModule::allocAckNak(err, to, idFrom, chIndex, hopLimit); +} + RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) { isPromiscuous = true; diff --git a/src/modules/RoutingModule.h b/src/modules/RoutingModule.h index a4e0679d0..5d4b9596f 100644 --- a/src/modules/RoutingModule.h +++ b/src/modules/RoutingModule.h @@ -16,6 +16,9 @@ class RoutingModule : public ProtobufModule virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0, bool ackWantsAck = false); + meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, + uint8_t hopLimit = 0); + // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit); diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index ad35e152a..7c33f0360 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -87,10 +87,13 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length) // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message. // We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node // receives it when we get our own packet back. Then we'll stop our retransmissions. - if (isFromUs(e.packet)) - routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index); - else + if (isFromUs(e.packet)) { + auto pAck = routingModule->allocAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index); + pAck->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT; + router->sendLocal(pAck); + } else { LOG_INFO("Ignore downlink message we originally sent"); + } return; } if (isFromUs(e.packet)) { diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 5d1ba20ba..472107229 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -337,7 +337,7 @@ void cpuDeepSleep(uint32_t msecToWake) #endif #ifdef TTGO_T_ECHO - // To power off the T-Echo, the display must be set + // To power off the T-Echo, the display must be set // as an input pin; otherwise, there will be leakage current. pinMode(PIN_EINK_CS, INPUT); pinMode(PIN_EINK_DC, INPUT);