From e528fa9c04a9d0352d26b1c1b481c46b81381a49 Mon Sep 17 00:00:00 2001 From: Masafumi Okada Date: Fri, 24 Apr 2026 09:08:24 +0900 Subject: [PATCH 01/52] Add QMP6988 telemetry sensor type --- meshtastic/telemetry.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index dccf1b6d8..f83cead40 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -891,6 +891,11 @@ enum TelemetrySensorType { * ICM-42607-P 6‑Axis IMU */ ICM42607P = 53; + + /* + * QMP6988 high accuracy pressure and temperature sensor + */ + QMP6988 = 54; } /* From a588ab5860f6e12b3d99b13fd1686583982de090 Mon Sep 17 00:00:00 2001 From: Randall Hand Date: Fri, 26 Jun 2026 15:59:04 -0400 Subject: [PATCH 02/52] docs(Position): correct ground_speed unit to km/h (matches firmware) The comment documents ground_speed as m/s, but the firmware transmits it in km/h. In meshtastic/firmware, GPS::lookForLocation() is the only place the GPS path sets the field: // src/gps/GPS.cpp p.ground_speed = reader.speed.kmph(); // TinyGPS++ .kmph() -> km/h PositionModule.cpp copies the value through unchanged. So the on-the-wire unit is km/h, and clients decoding it as m/s over-report speed by 3.6x. This updates the doc comment to match the implementation. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Randall Hand --- meshtastic/mesh.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index b1f219099..2fcc5f320 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -157,7 +157,7 @@ message Position { uint32 gps_accuracy = 14; /* - * Ground speed in m/s and True North TRACK in 1/100 degrees + * Ground speed in km/h and True North TRACK in 1/100 degrees * Clarification of terms: * - "track" is the direction of motion (measured in horizontal plane) * - "heading" is where the fuselage points (measured in horizontal plane) From 032b7dfd68e875c4323e6ac67590c6fc616b1714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 30 Jun 2026 22:15:09 +0200 Subject: [PATCH 03/52] Rename Seeed Tracker and add sensor (#967) * Rename Seeed Tracker and add sensor * uh, i'll kill that cat * Dear Copilot, stop messing with me --- meshtastic/mesh.proto | 4 ++-- meshtastic/telemetry.proto | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 6db4a6677..84879a260 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -876,10 +876,10 @@ enum HardwareModel { HELTEC_MESH_NODE_T096 = 127; /* - * Seeed studio T1000-E Pro tracker card. NRF52840 w/ LR2021 radio, + * Seeed studio Mesh Tracker X1card. NRF52840 w/ LR2021 radio, * GPS, button, buzzer, and sensors. */ - TRACKER_T1000_E_PRO = 128; + MESH_TRACKER_X1 = 128; /* * Elecrow ThinkNode M7, M8 and M9 diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index dccf1b6d8..e3b263640 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -891,6 +891,11 @@ enum TelemetrySensorType { * ICM-42607-P 6‑Axis IMU */ ICM42607P = 53; + + /* + * SPA06 pressure and temperature + */ + SPA06 = 54; } /* From 0b7ab7f9be6a6e7a5ea3be4b9857eca7a03e0b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 1 Jul 2026 13:41:24 +0200 Subject: [PATCH 04/52] Add LORA_OTA_APP portnum for firmware updates --- meshtastic/portnums.proto | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meshtastic/portnums.proto b/meshtastic/portnums.proto index 2b5fb8d54..944de2b7c 100644 --- a/meshtastic/portnums.proto +++ b/meshtastic/portnums.proto @@ -265,6 +265,12 @@ enum PortNum { * TAKPacketV2 with zstd dictionary compression. */ ATAK_PLUGIN_V2 = 78; + + /* signed firmware updates over lora. + * + * ENCODING: binary (ota-common transport frames) + */ + LORA_OTA_APP = 79; /* * GroupAlarm integration From 40ee6680bc23d3d3d37ed63eddd3c94563c3db2d Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Wed, 1 Jul 2026 10:20:57 -0700 Subject: [PATCH 05/52] Add is_unmessagable and is_licensed as fields for DeviceProfile exports --- meshtastic/clientonly.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/meshtastic/clientonly.proto b/meshtastic/clientonly.proto index c80f4289b..f6500005b 100644 --- a/meshtastic/clientonly.proto +++ b/meshtastic/clientonly.proto @@ -55,4 +55,14 @@ message DeviceProfile { * Predefined messages for CannedMessage */ optional string canned_messages = 8; + + /* + * Is the node unmessagable + */ + optional bool is_unmessagable = 9; + + /* + * Is this node in licensed user mode + */ + optional bool is_licensed = 10; } From 5ae1b2cce2a45b0e3d840175471c22b08c632a4a Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Wed, 1 Jul 2026 21:15:28 -0700 Subject: [PATCH 06/52] Set up a basic coderabbit yaml --- .coderabbit.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 000000000..97210a80c --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,15 @@ +language: en-US +reviews: + profile: chill + high_level_summary: true + poem: false + auto_review: + enabled: true + drafts: false + skip_author: + - renovate + - renovate[bot] + abort_on_close: true + + path_filters: + - "!/packages/**" From f68e94f033a2e72a8e88be41d54d52355cfe6cf5 Mon Sep 17 00:00:00 2001 From: Quency-D Date: Fri, 3 Jul 2026 18:07:24 +0800 Subject: [PATCH 07/52] Add Heltec RC series boards --- meshtastic/mesh.proto | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 84879a260..3bf6eca30 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -933,6 +933,21 @@ enum HardwareModel { */ MESHNOLOGY_W10 = 140; + /* + * Heltec ESP32S3 + SX1262 + */ + HELTEC_RC32 = 141; + + /* + * Heltec NRF52840 + SX1262 + */ + HELTEC_RC52 = 142; + + /* + * Heltec ESP32C6 + SX1262 + */ + HELTEC_RCC6 = 143; + /* * ------------------------------------------------------------------------------------------------------------------------------------------ * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. From 678281c41416b04c578e30c8b085bb8b648b15e7 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 6 Jul 2026 00:12:57 -0500 Subject: [PATCH 08/52] Fix formatting in portnums.proto (#976) --- meshtastic/portnums.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/portnums.proto b/meshtastic/portnums.proto index 944de2b7c..b517e15d8 100644 --- a/meshtastic/portnums.proto +++ b/meshtastic/portnums.proto @@ -265,7 +265,7 @@ enum PortNum { * TAKPacketV2 with zstd dictionary compression. */ ATAK_PLUGIN_V2 = 78; - + /* signed firmware updates over lora. * * ENCODING: binary (ota-common transport frames) From 9da731f1db65888275f84a1a8cc8b9f7361937e9 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:35:36 -0500 Subject: [PATCH 09/52] ci: make KMP snapshot versions sort by recency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Snapshots were named `--SNAPSHOT`. A git short SHA carries no chronological signal, and Maven's ComparableVersion tokenizes it as alpha/numeric garbage, so consumers' Renovate could not tell which snapshot was newest — "latest" resolved to latest-lexical, not latest-commit, and often bumped backwards. Switch to `git describe --tags --long`, yielding `--g-SNAPSHOT` where N is the commit count since the tag. N is a leading numeric token Maven compares numerically, so newer commits sort above older snapshots and Renovate picks the newest with no custom versioning. `--long` forces the `--g` suffix even on a tagged commit, so a bare `-SNAPSHOT` (which would sort below its base and trigger a downgrade) is never produced. The scheme still sorts above the tag's release and below the next release, preserving prior behavior. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/snapshot-kmp.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index 66582d675..afa4c1116 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -35,14 +35,16 @@ jobs: - name: Set version name run: | - # Name the snapshot after the latest tag (v-stripped) plus the short SHA. - # The `-` is a build qualifier, so Maven sorts this ABOVE the tag's - # release (no Renovate downgrade) yet below the next release — no patch - # bump needed. (The local fallback in build.gradle.kts uses a *bare* - # `-SNAPSHOT`, which sorts below its base, so it patch-bumps instead.) - BASE=$(git describe --tags --abbrev=0) - SHORT_SHA=${GITHUB_SHA::7} - echo "VERSION_NAME=${BASE#v}-${SHORT_SHA}-SNAPSHOT" >> "$GITHUB_ENV" + # Name the snapshot after the latest tag (v-stripped) plus the commit + # count since that tag and the short SHA, e.g. 2.7.26-82-g678281c-SNAPSHOT. + # The count is a *numeric* token, so Maven sorts newer commits ABOVE older + # snapshots — consumers' Renovate picks the newest by default, no custom + # versioning needed. It still sorts ABOVE the tag's release (no downgrade) + # and BELOW the next release. `--long` forces the --g suffix even on + # a tagged commit, so a bare `-SNAPSHOT` (which sorts below its base) is never + # produced. (The local fallback in build.gradle.kts still uses bare `-SNAPSHOT`.) + DESCRIBE=$(git describe --tags --long) + echo "VERSION_NAME=${DESCRIBE#v}-SNAPSHOT" >> "$GITHUB_ENV" - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp build -PVERSION_NAME=${{ env.VERSION_NAME }} From 993ae855e1ee37e1b82c92c2dd6affd554d762a6 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:46:32 -0500 Subject: [PATCH 10/52] docs: sync snapshot-versioning docs to git-describe --long scheme CodeRabbit flagged packages/kmp/README.md still describing the old `{tag}-{short-sha}-SNAPSHOT` scheme. Update the versioning table, the rationale paragraph, the Snapshots section, and the example coordinate to `{tag}-{N}-g{sha}-SNAPSHOT`, and note that the leading numeric commit count is what makes newer snapshots sort above older ones. Co-Authored-By: Claude Opus 4.8 --- packages/kmp/README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/kmp/README.md b/packages/kmp/README.md index cd8ec008d..57e467302 100644 --- a/packages/kmp/README.md +++ b/packages/kmp/README.md @@ -18,16 +18,17 @@ The SDK version is derived automatically from the latest git tag — no manual v | Context | Version | Source | |---------|---------|--------| | Release CI (`v2.7.23` tag push) | `2.7.23` | Tag stripped of `v` prefix, passed as `-PVERSION_NAME` | -| Snapshot CI (`master` push) | `2.7.23-497cd88-SNAPSHOT` | Latest tag, `v`-stripped + short commit SHA, passed as `-PVERSION_NAME` | +| Snapshot CI (`master` push) | `2.7.23-42-g497cd88-SNAPSHOT` | `git describe --tags --long`, `v`-stripped, passed as `-PVERSION_NAME` | | Local dev (no flag) | `2.7.24-SNAPSHOT` | `git describe --tags --abbrev=0` + patch bump | | Local override | any | `./gradlew build -PVERSION_NAME=x.y.z` | -CI snapshots keep the tag and append the SHA; local builds instead patch-bump. -The difference is deliberate: a `-` suffix is a build qualifier that sorts -*above* its base version, so CI can name the current tag and still land above -the release. A *bare* `-SNAPSHOT` sorts *below* its base, so the local fallback -names the next version to stay ahead of the last release. Both land between the -last and next release. +CI snapshots keep the tag and append the commit count since it (`N`) plus the +SHA; local builds instead patch-bump. The difference is deliberate: `-N-g` +leads with a *numeric* token, so Maven sorts newer commits above older snapshots +(dependency bots pick the newest) while the whole coordinate still sorts *above* +its base release and *below* the next one. A *bare* `-SNAPSHOT` sorts *below* its +base, so the local fallback names the next version to stay ahead of the last +release. Both land between the last and next release. If no `-PVERSION_NAME` is supplied and no tag can be resolved (git missing, or a shallow/tagless clone), the fallback degrades to `0.0.1-SNAPSHOT` rather than @@ -59,11 +60,12 @@ implementation("org.meshtastic:protobufs:2.7.23") ### Snapshots Every push to `master` publishes a snapshot under a unique coordinate of the -form `{latest-tag}-{short-sha}-SNAPSHOT` (e.g. `2.7.23-497cd88-SNAPSHOT`): the -latest release tag with its `v` stripped, plus the 7-char commit SHA. The -`-` suffix is a build qualifier, so Maven sorts each snapshot *above* the -release it was built from (dependency bots never propose a downgrade) yet -*below* the next release. They live in the Central Portal snapshots repository, +form `{latest-tag}-{N}-g{short-sha}-SNAPSHOT` (e.g. `2.7.23-42-g497cd88-SNAPSHOT`): +`git describe --tags --long` with the `v` stripped — the latest release tag, the +commit count `N` since that tag, and the 7-char commit SHA. The leading numeric +`N` makes Maven sort newer commits *above* older snapshots (dependency bots pick +the newest and never propose a downgrade) while each snapshot still sorts *above* +the release it was built from yet *below* the next release. They live in the Central Portal snapshots repository, not on the main Maven Central CDN. To consume them, add that repository alongside `mavenCentral()`: @@ -77,7 +79,7 @@ repositories { } // build.gradle.kts — pin a specific published snapshot -implementation("org.meshtastic:protobufs:2.7.23-497cd88-SNAPSHOT") +implementation("org.meshtastic:protobufs:2.7.23-42-g497cd88-SNAPSHOT") ``` Each `master` push produces a new coordinate, so pin a specific one and bump it From ecf2ed47616d505e6d3591719f97d688cfd6823b Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:55:26 -0500 Subject: [PATCH 11/52] ci: separate snapshot count with a dot so it outranks legacy SHA snapshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the git-describe --long change. That put the commit count in `{tag}-{N}-g{sha}-SNAPSHOT`, but the count shares a hyphen level with the old `{tag}-{sha}-SNAPSHOT` snapshots still published in the repo. A short SHA can tokenize to a large integer (e.g. `678281c` -> 678281) that dwarfs the count (e.g. 88), so in Maven's ComparableVersion the legacy snapshot still sorts highest and dependency bots keep pointing at it — the new scheme is masked and never picked. Move the count after a dot: `{tag}.{N}-g{sha}-SNAPSHOT`. A dot-separated numeric segment outranks any hyphen-nested token, so the new snapshots sort above every legacy `--SNAPSHOT` regardless of the SHA's leading digits, while still sorting above the tag's release and below the next release, and ordering among themselves by count. Verified against maven-artifact 3.9.9 ComparableVersion: 2.7.26-678281c-SNAPSHOT < 2.7.26.88-gd77b460-SNAPSHOT < 2.7.27 Also add workflow_dispatch so the scheme change (which touches only this workflow, outside the push-path filter) can be published on demand. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/snapshot-kmp.yml | 33 +++++++++++++++++++++--------- packages/kmp/README.md | 31 ++++++++++++++++------------ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index afa4c1116..f707cb768 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -8,6 +8,9 @@ on: - "meshtastic/**/*.proto" - "nanopb.proto" - "packages/kmp/**" + # Allow republishing on demand (e.g. after a versioning-scheme change that + # touches only this workflow, which the push paths above don't match). + workflow_dispatch: permissions: contents: read @@ -35,16 +38,26 @@ jobs: - name: Set version name run: | - # Name the snapshot after the latest tag (v-stripped) plus the commit - # count since that tag and the short SHA, e.g. 2.7.26-82-g678281c-SNAPSHOT. - # The count is a *numeric* token, so Maven sorts newer commits ABOVE older - # snapshots — consumers' Renovate picks the newest by default, no custom - # versioning needed. It still sorts ABOVE the tag's release (no downgrade) - # and BELOW the next release. `--long` forces the --g suffix even on - # a tagged commit, so a bare `-SNAPSHOT` (which sorts below its base) is never - # produced. (The local fallback in build.gradle.kts still uses bare `-SNAPSHOT`.) - DESCRIBE=$(git describe --tags --long) - echo "VERSION_NAME=${DESCRIBE#v}-SNAPSHOT" >> "$GITHUB_ENV" + # Name the snapshot after the latest tag (v-stripped), the commit count + # since that tag, and the short SHA, e.g. 2.7.26.88-gd77b460-SNAPSHOT. + # + # The count goes after a DOT, not a hyphen, and that is load-bearing. In + # Maven's ComparableVersion a dot-separated numeric segment outranks ANY + # hyphen-nested token, so these sort ABOVE the legacy `--SNAPSHOT` + # snapshots still in the repo — whose SHA can tokenize to a huge integer + # (e.g. 678281c -> 678281) that would otherwise dwarf the count and mask + # every new snapshot from dependency bots. Among themselves, higher count = + # newer commit sorts higher, so bots pick the newest. Still sorts ABOVE the + # tag's release (no downgrade) and BELOW the next release. `--long` forces + # the --g suffix even on a tagged commit, so a bare `-SNAPSHOT` + # (which sorts below its base) is never produced. (Local fallback in + # build.gradle.kts still uses bare `-SNAPSHOT`.) + # + # Parsed right-to-left (describe = --g) so a hyphenated tag + # like v1.2.3-rc1 would still split correctly. + DESCRIBE=$(git describe --tags --long); DESCRIBE=${DESCRIBE#v} + SHA=${DESCRIBE##*-}; REST=${DESCRIBE%-*}; COUNT=${REST##*-}; TAG=${REST%-*} + echo "VERSION_NAME=${TAG}.${COUNT}-${SHA}-SNAPSHOT" >> "$GITHUB_ENV" - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp build -PVERSION_NAME=${{ env.VERSION_NAME }} diff --git a/packages/kmp/README.md b/packages/kmp/README.md index 57e467302..4263a7999 100644 --- a/packages/kmp/README.md +++ b/packages/kmp/README.md @@ -18,17 +18,20 @@ The SDK version is derived automatically from the latest git tag — no manual v | Context | Version | Source | |---------|---------|--------| | Release CI (`v2.7.23` tag push) | `2.7.23` | Tag stripped of `v` prefix, passed as `-PVERSION_NAME` | -| Snapshot CI (`master` push) | `2.7.23-42-g497cd88-SNAPSHOT` | `git describe --tags --long`, `v`-stripped, passed as `-PVERSION_NAME` | +| Snapshot CI (`master` push) | `2.7.23.42-g497cd88-SNAPSHOT` | `git describe --tags --long`, `v`-stripped, count after a dot, passed as `-PVERSION_NAME` | | Local dev (no flag) | `2.7.24-SNAPSHOT` | `git describe --tags --abbrev=0` + patch bump | | Local override | any | `./gradlew build -PVERSION_NAME=x.y.z` | CI snapshots keep the tag and append the commit count since it (`N`) plus the -SHA; local builds instead patch-bump. The difference is deliberate: `-N-g` -leads with a *numeric* token, so Maven sorts newer commits above older snapshots -(dependency bots pick the newest) while the whole coordinate still sorts *above* -its base release and *below* the next one. A *bare* `-SNAPSHOT` sorts *below* its -base, so the local fallback names the next version to stay ahead of the last -release. Both land between the last and next release. +SHA; local builds instead patch-bump. The count goes after a *dot* (`{tag}.{N}`), +which is deliberate: in Maven's ordering a dot-separated numeric segment outranks +any hyphen-nested token, so a newer commit's higher count sorts above older +snapshots — including legacy `{tag}-{sha}-SNAPSHOT` builds still in the repo whose +SHA can tokenize to a large integer — while the whole coordinate still sorts +*above* its base release and *below* the next one. Dependency bots therefore pick +the newest. A *bare* `-SNAPSHOT` sorts *below* its base, so the local fallback +names the next version to stay ahead of the last release. Both land between the +last and next release. If no `-PVERSION_NAME` is supplied and no tag can be resolved (git missing, or a shallow/tagless clone), the fallback degrades to `0.0.1-SNAPSHOT` rather than @@ -60,12 +63,14 @@ implementation("org.meshtastic:protobufs:2.7.23") ### Snapshots Every push to `master` publishes a snapshot under a unique coordinate of the -form `{latest-tag}-{N}-g{short-sha}-SNAPSHOT` (e.g. `2.7.23-42-g497cd88-SNAPSHOT`): +form `{latest-tag}.{N}-g{short-sha}-SNAPSHOT` (e.g. `2.7.23.42-g497cd88-SNAPSHOT`): `git describe --tags --long` with the `v` stripped — the latest release tag, the -commit count `N` since that tag, and the 7-char commit SHA. The leading numeric -`N` makes Maven sort newer commits *above* older snapshots (dependency bots pick -the newest and never propose a downgrade) while each snapshot still sorts *above* -the release it was built from yet *below* the next release. They live in the Central Portal snapshots repository, +commit count `N` since that tag (after a **dot**), and the 7-char commit SHA. The +dot-separated numeric `N` outranks any hyphen-nested token in Maven's ordering, so +newer commits sort *above* older snapshots — including legacy `{tag}-{sha}` builds +still in the repo — letting dependency bots pick the newest and never downgrade, +while each snapshot still sorts *above* the release it was built from yet *below* +the next release. They live in the Central Portal snapshots repository, not on the main Maven Central CDN. To consume them, add that repository alongside `mavenCentral()`: @@ -79,7 +84,7 @@ repositories { } // build.gradle.kts — pin a specific published snapshot -implementation("org.meshtastic:protobufs:2.7.23-42-g497cd88-SNAPSHOT") +implementation("org.meshtastic:protobufs:2.7.23.42-g497cd88-SNAPSHOT") ``` Each `master` push produces a new coordinate, so pin a specific one and bump it From a5056344bf7058ad7901117a32225dc064904086 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 11 Jul 2026 05:39:36 -0500 Subject: [PATCH 12/52] Add MEDIUM_TURBO modem preset Medium range preset comparable to MEDIUM_FAST but with 500kHz bandwidth. --- meshtastic/config.proto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meshtastic/config.proto b/meshtastic/config.proto index aa5264e2c..c9a718f45 100644 --- a/meshtastic/config.proto +++ b/meshtastic/config.proto @@ -1100,6 +1100,13 @@ message Config { * Comparable link budget and data rate to LONG_MODERATE. */ TINY_SLOW = 15; + + /* + * Medium Range - Turbo + * This preset performs similarly to MEDIUM_FAST, but with 500kHz bandwidth. + * It is not legal to use in all regions due to this wider bandwidth. + */ + MEDIUM_TURBO = 16; } enum FEM_LNA_Mode { From da2fc413931c81c1d2bc9b6a838d739e2bf35bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 13 Jul 2026 12:01:36 +0200 Subject: [PATCH 13/52] Indicator (#721) --- meshtastic/interdevice.options | 10 ++ meshtastic/interdevice.proto | 180 ++++++++++++++++++++++++++++----- 2 files changed, 165 insertions(+), 25 deletions(-) diff --git a/meshtastic/interdevice.options b/meshtastic/interdevice.options index 97df282f7..017a0525f 100644 --- a/meshtastic/interdevice.options +++ b/meshtastic/interdevice.options @@ -1 +1,11 @@ *InterdeviceMessage.nmea max_size:1024 +*InterdeviceMessage.beep int_size:16 +*InterdeviceMessage.i2c_scan_result max_size:128 +*I2CTransaction.write_data max_size:256 +*I2CResult.read_data max_size:256 +*DirectoryListing.filenames max_length:255 max_count:16 +*DirectoryListing.directory max_size:256 +*DirectoryListing.message max_size:255 +*FileTransfer.filedata max_size:4096 +*FileTransfer.filepath max_size:256 +*FileTransfer.message max_size:255 diff --git a/meshtastic/interdevice.proto b/meshtastic/interdevice.proto index f646368b2..760bc810b 100644 --- a/meshtastic/interdevice.proto +++ b/meshtastic/interdevice.proto @@ -8,37 +8,167 @@ option java_outer_classname = "InterdeviceProtos"; option java_package = "org.meshtastic.proto"; option swift_prefix = ""; -// encapsulate up to 1k of NMEA string data - -enum MessageType { - ACK = 0; - COLLECT_INTERVAL = 160; // in ms - BEEP_ON = 161; // duration ms - BEEP_OFF = 162; // cancel prematurely - SHUTDOWN = 163; - POWER_ON = 164; - SCD41_TEMP = 176; - SCD41_HUMIDITY = 177; - SCD41_CO2 = 178; - AHT20_TEMP = 179; - AHT20_HUMIDITY = 180; - TVOC_INDEX = 181; -} - -message SensorData { - // The message type - MessageType type = 1; - // The sensor data, either as a float or an uint32 - oneof data { - float float_value = 2; - uint32 uint32_value = 3; +// Version of the interdevice protocol spoken on the link. Both sides send +// theirs in the ping/pong handshake; a peer reporting a different one runs +// firmware that does not match and is not talked to. +// +// On a change that breaks the other side (renumbered fields, changed +// semantics, removed messages), raise the value of CURRENT. Do not add +// another entry: this enum carries a single constant, not a history. +enum InterdeviceVersion { + INTERDEVICE_VERSION_UNSPECIFIED = 0; + // Never use 1: ping/pong were bools before the handshake existed, and a + // bool true is the same varint on the wire as the number 1, so firmware + // predating the handshake would pass it. + INTERDEVICE_VERSION_CURRENT = 2; +} + +// Defines the supported file operations +enum FileOperation { + GET = 0; + POST = 1; + PUT = 2; + DELETE = 3; +} + +// Outcome of a file or directory operation. The requester must be able to +// tell a transient condition from a definitive one: BUSY is worth another +// try, NOT_FOUND is not. +enum FileStatus { + FILE_UNSPECIFIED = 0; + FILE_OK = 1; + // Retry later: the co-processor is doing card maintenance (mount, + // free space scan) and cannot serve the request right now + FILE_BUSY = 2; + FILE_NO_CARD = 3; + FILE_NOT_FOUND = 4; + // PUT only: offset did not match the current end of the file. file_size + // carries the size the file actually has, so the writer can resync (or + // recognize its own chunk as already written after a lost response). + FILE_OFFSET_CONFLICT = 5; + FILE_IO_ERROR = 6; + FILE_NOT_A_FILE = 7; // path is a directory (GET) or not one (listing) +} + +// Message for file operations +message FileTransfer { + FileOperation operation = 1; // File operation (GET, POST, PUT, DELETE) + string filepath = 2; // Path of the file on the SD card + bytes filedata = 3; // Chunk content (POST/PUT request, GET response) + FileStatus status = 4; // Response: outcome of the operation + string message = 5; // Response: human readable detail, may be empty + uint64 offset = 6; // Byte offset of this chunk within the file (ranged GET/PUT) + // GET request: number of bytes to read, 0 = max chunk size. A response + // carries at most the filedata max_size (see interdevice.options) per + // chunk; larger requests are truncated, visible in the filedata length. + uint32 length = 7; + uint64 file_size = 8; // GET response: total size of the file +} + +// Message for structured directory listing +message DirectoryListing { + string directory = 1; // Path of the directory + // One page of entry names, full FAT LFN length. Subdirectories carry a + // trailing slash. Note that a name whose directory prefix pushes the + // combined path past the FileTransfer.filepath limit cannot round-trip. + // Page size is the max_count in interdevice.options; page through with + // offset and total_count. + repeated string filenames = 2; + FileStatus status = 3; // Response: outcome of the operation + string message = 4; // Response: human readable detail, may be empty + uint32 offset = 5; // Request: skip this many entries (paging) + uint32 total_count = 6; // Response: total number of entries in the directory +} + +// A single I2C transaction: an optional write followed by an optional +// read with repeated start, matching the TwoWire usage of sensor drivers +// (beginTransmission/write.../endTransmission(false)/requestFrom) +message I2CTransaction { + uint32 address = 1; // 7-bit device address + bytes write_data = 2; // Bytes to write, may be empty + // Number of bytes to read after the write, 0 = write-only. Bounded by + // the read_data max_size of I2CResult (see interdevice.options); larger + // requests are truncated, visible in the returned byte count. + uint32 read_len = 3; +} + +// SD card statistics +message SdCardInfo { + enum CardType { + NONE = 0; + MMC = 1; + SD = 2; + SDHC = 3; + SDXC = 4; + UNKNOWN_CARD = 5; + } + enum FatType { + UNKNOWN_FAT = 0; + FAT16 = 1; + FAT32 = 2; + EXFAT = 3; + } + // Card initialized and usable. False while `busy` is set does not mean + // there is no card: the co-processor does not know yet. + bool present = 1; + CardType card_type = 2; + FatType fat_type = 3; + uint64 card_size = 4; // Filesystem size in bytes + uint64 used_bytes = 5; // Used bytes (may be expensive to compute on FAT32) + uint64 free_bytes = 6; // Free bytes + // used_bytes/free_bytes are only meaningful when true: the scan behind + // them runs in the background after mount and can take a while, and a + // full card is otherwise indistinguishable from a scan in progress + bool stats_valid = 7; + // The co-processor is mounting a card right now, so whether one is + // present is not decided yet. Ask again rather than concluding the slot + // is empty. + bool busy = 8; +} + +// Result of an I2CTransaction +message I2CResult { + enum Status { + // Never sent: an all-defaults (e.g. accidentally empty) message must + // not decode as a successful transaction + UNSPECIFIED = 0; + OK = 1; + NACK_ADDRESS = 2; + NACK_DATA = 3; + ERROR = 4; } + Status status = 1; + bytes read_data = 2; // Data read from the device, empty for write-only transactions } +// Main message for interdevice communication message InterdeviceMessage { + // Correlates a response with its request: responses echo the id of the + // request they answer. 0 for unsolicited messages (e.g. the nmea stream). + uint32 id = 15; // The message data oneof data { string nmea = 1; - SensorData sensor = 2; + uint32 beep = 2; + I2CTransaction i2c_transaction = 3; + I2CResult i2c_result = 4; + bool i2c_scan = 5; // Request: scan the secondary I2C bus + bytes i2c_scan_result = 6; // Response: 7-bit addresses of discovered devices + FileTransfer file_transfer = 7; + DirectoryListing directory_listing = 8; + bool get_sd_info = 9; // Request: SD card statistics + SdCardInfo sd_info = 10; // Response + // Link liveness probe and version handshake. The receiver answers ping + // with pong, echoing the id. Touches no peripherals, so it works with + // nothing attached. Both carry the version the sender speaks; a peer + // that answers with a different one speaks another protocol and must + // not be used. + InterdeviceVersion ping = 11; + InterdeviceVersion pong = 12; + // Response: the request could not be decoded or is of an unhandled + // type, so the requester fails fast instead of burning its timeout. + // Echoes the id when known, 0 when the frame was undecodable. Never + // sent in reaction to a nack. + bool nack = 13; } } From 821d89b2874105a788b1d57be706afb428f1f4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 15 Jul 2026 16:46:49 +0200 Subject: [PATCH 14/52] interdevice: SD card mount, eject and format commands (#986) --- meshtastic/interdevice.proto | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/meshtastic/interdevice.proto b/meshtastic/interdevice.proto index 760bc810b..62478a7f9 100644 --- a/meshtastic/interdevice.proto +++ b/meshtastic/interdevice.proto @@ -124,6 +124,17 @@ message SdCardInfo { // present is not decided yet. Ask again rather than concluding the slot // is empty. bool busy = 8; + // A card answers in the slot but carries no filesystem that could be + // mounted (present is false then). Formatting it makes it usable. + bool unformatted = 9; +} + +// What to do with the SD card of the co-processor +enum SdCommand { + SD_COMMAND_UNSPECIFIED = 0; + SD_MOUNT = 1; // mount a card that is in the slot, also after an eject + SD_EJECT = 2; // flush and release the card so it can be pulled safely + SD_FORMAT = 3; // wipe the card and put a fresh FAT on it, then mount it } // Result of an I2CTransaction @@ -170,5 +181,10 @@ message InterdeviceMessage { // Echoes the id when known, 0 when the frame was undecodable. Never // sent in reaction to a nack. bool nack = 13; + // Request: mount the card, or release it so it can be pulled safely. The + // co-processor answers with sd_info. Without an eject the card is mounted + // on its own and kept mounted; after one it stays released until a mount + // is asked for. + SdCommand sd_command = 14; } } From 223e20ebbd5dc4189ff9a775fc9c8817260e57ba Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Thu, 9 Jul 2026 12:55:41 -0700 Subject: [PATCH 15/52] feat: add packet signature policy schema --- meshtastic/config.proto | 28 ++++++++++++++++++++++++++++ meshtastic/interdevice.proto | 34 +++++++++++++++++----------------- meshtastic/mesh.proto | 6 ++++++ 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/meshtastic/config.proto b/meshtastic/config.proto index c9a718f45..a02e019df 100644 --- a/meshtastic/config.proto +++ b/meshtastic/config.proto @@ -1293,6 +1293,29 @@ message Config { } message SecurityConfig { + /* + * Controls how the device authenticates remotely received mesh packets. + */ + enum PacketSignaturePolicy { + /* + * Accept unsigned packets for maximum compatibility while still rejecting malformed or invalid signatures. + * This is the default to avoid legacy nodes dropping signed packets during rebroadcast. + */ + PACKET_SIGNATURE_POLICY_COMPATIBLE = 0; + + /* + * Prefer authenticated packets while retaining compatibility with unsigned packets from nodes not known to sign. + * Rejects unsigned, signable broadcasts from nodes that have previously signed. + */ + PACKET_SIGNATURE_POLICY_BALANCED = 1; + + /* + * Accept only packets authenticated by a verified XEdDSA signature or successful PKI decryption. + * Unsigned, malformed, invalid, or unverifiable packets are ignored. + */ + PACKET_SIGNATURE_POLICY_STRICT = 2; + } + /* * The public key of the user's device. * Sent out to other nodes on the mesh to allow them to compute a shared secret key. @@ -1331,6 +1354,11 @@ message Config { * Allow incoming device control over the insecure legacy admin channel. */ bool admin_channel_enabled = 8; + + /* + * Determines the packet signature policy applied to remotely received mesh packets. + */ + PacketSignaturePolicy packet_signature_policy = 9; } /* diff --git a/meshtastic/interdevice.proto b/meshtastic/interdevice.proto index 62478a7f9..a0be6a7c3 100644 --- a/meshtastic/interdevice.proto +++ b/meshtastic/interdevice.proto @@ -53,38 +53,38 @@ enum FileStatus { // Message for file operations message FileTransfer { FileOperation operation = 1; // File operation (GET, POST, PUT, DELETE) - string filepath = 2; // Path of the file on the SD card - bytes filedata = 3; // Chunk content (POST/PUT request, GET response) - FileStatus status = 4; // Response: outcome of the operation - string message = 5; // Response: human readable detail, may be empty - uint64 offset = 6; // Byte offset of this chunk within the file (ranged GET/PUT) + string filepath = 2; // Path of the file on the SD card + bytes filedata = 3; // Chunk content (POST/PUT request, GET response) + FileStatus status = 4; // Response: outcome of the operation + string message = 5; // Response: human readable detail, may be empty + uint64 offset = 6; // Byte offset of this chunk within the file (ranged GET/PUT) // GET request: number of bytes to read, 0 = max chunk size. A response // carries at most the filedata max_size (see interdevice.options) per // chunk; larger requests are truncated, visible in the filedata length. uint32 length = 7; - uint64 file_size = 8; // GET response: total size of the file + uint64 file_size = 8; // GET response: total size of the file } // Message for structured directory listing message DirectoryListing { - string directory = 1; // Path of the directory + string directory = 1; // Path of the directory // One page of entry names, full FAT LFN length. Subdirectories carry a // trailing slash. Note that a name whose directory prefix pushes the // combined path past the FileTransfer.filepath limit cannot round-trip. // Page size is the max_count in interdevice.options; page through with // offset and total_count. repeated string filenames = 2; - FileStatus status = 3; // Response: outcome of the operation - string message = 4; // Response: human readable detail, may be empty - uint32 offset = 5; // Request: skip this many entries (paging) - uint32 total_count = 6; // Response: total number of entries in the directory + FileStatus status = 3; // Response: outcome of the operation + string message = 4; // Response: human readable detail, may be empty + uint32 offset = 5; // Request: skip this many entries (paging) + uint32 total_count = 6; // Response: total number of entries in the directory } // A single I2C transaction: an optional write followed by an optional // read with repeated start, matching the TwoWire usage of sensor drivers // (beginTransmission/write.../endTransmission(false)/requestFrom) message I2CTransaction { - uint32 address = 1; // 7-bit device address + uint32 address = 1; // 7-bit device address bytes write_data = 2; // Bytes to write, may be empty // Number of bytes to read after the write, 0 = write-only. Bounded by // the read_data max_size of I2CResult (see interdevice.options); larger @@ -113,7 +113,7 @@ message SdCardInfo { bool present = 1; CardType card_type = 2; FatType fat_type = 3; - uint64 card_size = 4; // Filesystem size in bytes + uint64 card_size = 4; // Filesystem size in bytes uint64 used_bytes = 5; // Used bytes (may be expensive to compute on FAT32) uint64 free_bytes = 6; // Free bytes // used_bytes/free_bytes are only meaningful when true: the scan behind @@ -132,8 +132,8 @@ message SdCardInfo { // What to do with the SD card of the co-processor enum SdCommand { SD_COMMAND_UNSPECIFIED = 0; - SD_MOUNT = 1; // mount a card that is in the slot, also after an eject - SD_EJECT = 2; // flush and release the card so it can be pulled safely + SD_MOUNT = 1; // mount a card that is in the slot, also after an eject + SD_EJECT = 2; // flush and release the card so it can be pulled safely SD_FORMAT = 3; // wipe the card and put a fresh FAT on it, then mount it } @@ -163,11 +163,11 @@ message InterdeviceMessage { uint32 beep = 2; I2CTransaction i2c_transaction = 3; I2CResult i2c_result = 4; - bool i2c_scan = 5; // Request: scan the secondary I2C bus + bool i2c_scan = 5; // Request: scan the secondary I2C bus bytes i2c_scan_result = 6; // Response: 7-bit addresses of discovered devices FileTransfer file_transfer = 7; DirectoryListing directory_listing = 8; - bool get_sd_info = 9; // Request: SD card statistics + bool get_sd_info = 9; // Request: SD card statistics SdCardInfo sd_info = 10; // Response // Link liveness probe and version handshake. The receiver answers ping // with pong, echoing the id. Touches no peripherals, so it works with diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 3bf6eca30..4d9e4808b 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -2762,6 +2762,12 @@ message DeviceMetadata { * (bitwise OR of ExcludedModules) */ uint32 excluded_modules = 12; + + /* + * Indicates whether this firmware build includes XEdDSA packet signature verification. + * This is a read-only capability and must be false when XEdDSA is not compiled in. + */ + bool has_xeddsa = 14; } /* From 5f16928d917113811b6657d9e8ba802f7a273557 Mon Sep 17 00:00:00 2001 From: Oleksandr Kravchuk Date: Wed, 15 Jul 2026 20:55:33 +0200 Subject: [PATCH 16/52] Deprecate EU_868 region code Ukrainian legislation* was harmonised with the EU's, and UA_868 is now obsolete as it is identical to the EU_868. * https://zakon.rada.gov.ua/laws/show/262-2026-%D0%BF --- meshtastic/config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/config.proto b/meshtastic/config.proto index c9a718f45..9ed041f83 100644 --- a/meshtastic/config.proto +++ b/meshtastic/config.proto @@ -878,7 +878,7 @@ message Config { /* * Ukraine 868mhz */ - UA_868 = 15; + UA_868 = 15 [deprecated = true]; /* * Malaysia 433mhz From 7b46dfbf5750093a9fba7469fba10b5bc5be021c Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Thu, 16 Jul 2026 13:53:23 +0200 Subject: [PATCH 17/52] Add HM330X sensor --- meshtastic/telemetry.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index e3b263640..53b1bedfb 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -896,6 +896,11 @@ enum TelemetrySensorType { * SPA06 pressure and temperature */ SPA06 = 54; + + /* + * HM330X PM SENSOR + */ + HM330X = 55; } /* From f1c8403905b4acf3fdf2806770c6500dacf64296 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 13:34:33 +0000 Subject: [PATCH 18/52] Update plugin com.squareup.wire to v6.4.5 --- packages/kmp/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/build.gradle.kts b/packages/kmp/build.gradle.kts index 4b432c860..3658ba038 100644 --- a/packages/kmp/build.gradle.kts +++ b/packages/kmp/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") version "2.4.0" id("com.android.kotlin.multiplatform.library") version "9.2.1" - id("com.squareup.wire") version "6.4.0" + id("com.squareup.wire") version "6.4.5" id("com.vanniktech.maven.publish") version "0.36.0" } From 39a66709fef898a2c2847aec42813e42a8ca9e39 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 18 Jul 2026 06:02:24 -0500 Subject: [PATCH 19/52] feat: add FAB firmware edition Adds FAB = 20 to FirmwareEdition for FAB26 Boston and future editions of the international Fab Lab digital fabrication conference. Fills the next sequential event slot after HAMVENTION = 19. Co-Authored-By: Claude Opus 4.8 --- meshtastic/mesh.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 3bf6eca30..88bfebb79 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -2167,6 +2167,11 @@ enum FirmwareEdition { */ HAMVENTION = 19; + /* + * FAB, the international Fab Lab digital fabrication conference + */ + FAB = 20; + /* * Placeholder for DIY and unofficial events */ From 8f9aa65f15331a831099a94d3927eb7216c75581 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 11:09:03 +0000 Subject: [PATCH 20/52] Update plugin org.jetbrains.kotlin.multiplatform to v2.4.10 --- packages/kmp/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/build.gradle.kts b/packages/kmp/build.gradle.kts index 4b432c860..2dcbc1764 100644 --- a/packages/kmp/build.gradle.kts +++ b/packages/kmp/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("multiplatform") version "2.4.0" + kotlin("multiplatform") version "2.4.10" id("com.android.kotlin.multiplatform.library") version "9.2.1" id("com.squareup.wire") version "6.4.0" id("com.vanniktech.maven.publish") version "0.36.0" From 7d8373b9e2b0ed0c45a5aa08ebb6ee609346823b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 11:09:48 +0000 Subject: [PATCH 21/52] Update bufbuild/buf-action action to v1.4.0 --- .github/workflows/create_tag.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/schema-registry.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index 951faeb09..8d6fc59dd 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -58,7 +58,7 @@ jobs: token: ${{ github.token }} - name: Setup Buf - uses: bufbuild/buf-action@v1.2.0 + uses: bufbuild/buf-action@v1.4.0 with: version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index e47672c8d..a05991abf 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@v4 - name: Buf PR Checks - uses: bufbuild/buf-action@v1.2.0 + uses: bufbuild/buf-action@v1.4.0 with: version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} diff --git a/.github/workflows/schema-registry.yml b/.github/workflows/schema-registry.yml index 8a21c713b..95d26414f 100644 --- a/.github/workflows/schema-registry.yml +++ b/.github/workflows/schema-registry.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v4 - name: Push to schema registry - uses: bufbuild/buf-action@v1.2.0 + uses: bufbuild/buf-action@v1.4.0 with: version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} From bdfd7fc2f05d2205ab3b306ffcb5a3ebc9f64979 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 11:27:42 +0000 Subject: [PATCH 22/52] Update dependency bufbuild/buf to v1.72.0 --- .github/workflows/create_tag.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/schema-registry.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index 8d6fc59dd..b0823c335 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -60,7 +60,7 @@ jobs: - name: Setup Buf uses: bufbuild/buf-action@v1.4.0 with: - version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf + version: 1.72.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} token: ${{ secrets.BUF_TOKEN }} setup_only: true diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index a05991abf..dbf4bedf4 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -16,7 +16,7 @@ jobs: - name: Buf PR Checks uses: bufbuild/buf-action@v1.4.0 with: - version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf + version: 1.72.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} token: ${{ secrets.BUF_TOKEN }} format: true diff --git a/.github/workflows/schema-registry.yml b/.github/workflows/schema-registry.yml index 95d26414f..ab578a9a0 100644 --- a/.github/workflows/schema-registry.yml +++ b/.github/workflows/schema-registry.yml @@ -19,7 +19,7 @@ jobs: - name: Push to schema registry uses: bufbuild/buf-action@v1.4.0 with: - version: 1.71.0 # renovate: datasource=github-releases depName=bufbuild/buf + version: 1.72.0 # renovate: datasource=github-releases depName=bufbuild/buf github_token: ${{ github.token }} token: ${{ secrets.BUF_TOKEN }} push: true From 84fcb58d16498b0614b78de6176b7ecfea3d60a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:32:14 -0500 Subject: [PATCH 23/52] Update Gradle to v9.6.1 (#1001) --- packages/kmp/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/gradle/wrapper/gradle-wrapper.properties b/packages/kmp/gradle/wrapper/gradle-wrapper.properties index df6a6ad76..a9db11550 100644 --- a/packages/kmp/gradle/wrapper/gradle-wrapper.properties +++ b/packages/kmp/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 63f15a7fab404f860d6c6d7873119a2abebd583f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:32:40 -0500 Subject: [PATCH 24/52] Update dependency com.squareup.wire:wire-runtime to v6.4.5 (#992) --- packages/kmp/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/build.gradle.kts b/packages/kmp/build.gradle.kts index c44dc592a..46b7eed2a 100644 --- a/packages/kmp/build.gradle.kts +++ b/packages/kmp/build.gradle.kts @@ -64,7 +64,7 @@ kotlin { sourceSets { commonMain { dependencies { - api("com.squareup.wire:wire-runtime:6.4.0") + api("com.squareup.wire:wire-runtime:6.4.5") } } } From 3703b06e9d1a7344cae70b29e8a75d02e42cd486 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:33:03 -0500 Subject: [PATCH 25/52] Update plugin com.android.kotlin.multiplatform.library to v9.3.0 (#1002) --- packages/kmp/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/build.gradle.kts b/packages/kmp/build.gradle.kts index 46b7eed2a..da3f0c726 100644 --- a/packages/kmp/build.gradle.kts +++ b/packages/kmp/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("multiplatform") version "2.4.10" - id("com.android.kotlin.multiplatform.library") version "9.2.1" + id("com.android.kotlin.multiplatform.library") version "9.3.0" id("com.squareup.wire") version "6.4.5" id("com.vanniktech.maven.publish") version "0.36.0" } From 164b6e25b397d310a5ce0e092c428077b874cef3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:33:41 -0500 Subject: [PATCH 26/52] Update plugin com.vanniktech.maven.publish to v0.37.0 (#1003) --- packages/kmp/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kmp/build.gradle.kts b/packages/kmp/build.gradle.kts index da3f0c726..d48c6d25e 100644 --- a/packages/kmp/build.gradle.kts +++ b/packages/kmp/build.gradle.kts @@ -2,7 +2,7 @@ plugins { kotlin("multiplatform") version "2.4.10" id("com.android.kotlin.multiplatform.library") version "9.3.0" id("com.squareup.wire") version "6.4.5" - id("com.vanniktech.maven.publish") version "0.36.0" + id("com.vanniktech.maven.publish") version "0.37.0" } group = providers.gradleProperty("GROUP").get() From ec5bad2a2fdbfaf77a2578a30a156d1de292c530 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:35:25 -0500 Subject: [PATCH 27/52] Update softprops/action-gh-release action to v3 (#1011) --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 89e5aec63..231843a84 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -183,7 +183,7 @@ jobs: name: release_zips - name: Upload assets to GitHub release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ needs.codegen.outputs.tag }} files: | From 0ed6f2c85be8beec96fbe713717f7398fe33c59d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:35:50 -0500 Subject: [PATCH 28/52] Update gradle/actions action to v6 (#1010) --- .github/workflows/kmp-pull-request.yml | 2 +- .github/workflows/publish-kmp.yml | 4 ++-- .github/workflows/snapshot-kmp.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/kmp-pull-request.yml b/.github/workflows/kmp-pull-request.yml index ca934e887..ff84c6ad0 100644 --- a/.github/workflows/kmp-pull-request.yml +++ b/.github/workflows/kmp-pull-request.yml @@ -27,7 +27,7 @@ jobs: uses: android-actions/setup-android@v3 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v6 - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp build -PVERSION_NAME=0.0.0-pr diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index 2fe0c535d..add6dd9bc 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -57,7 +57,7 @@ jobs: uses: android-actions/setup-android@v3 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v6 - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp clean build -PVERSION_NAME=${{ steps.version.outputs.VERSION }} @@ -85,7 +85,7 @@ jobs: uses: android-actions/setup-android@v3 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v6 - name: Publish to Maven Central env: diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index f707cb768..42c1db5fa 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -34,7 +34,7 @@ jobs: uses: android-actions/setup-android@v3 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v6 - name: Set version name run: | From c1f14c4584b48aa7eca929f4dfaa46d713ec51b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:36:43 -0500 Subject: [PATCH 29/52] Update GitHub Artifact Actions (major) (#1009) --- .github/workflows/publish.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 231843a84..d40e8cdb0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -88,7 +88,7 @@ jobs: run: cp LICENSE README.md packages/ts/ - name: Upload TypeScript code - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ts_code path: packages/ts @@ -98,7 +98,7 @@ jobs: needs: codegen steps: - name: Download TypeScript code - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: ts_code @@ -127,7 +127,7 @@ jobs: ls -la ls -la dist/ - name: Upload built NPM package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: npm_package path: | @@ -136,7 +136,7 @@ jobs: LICENSE README.md - name: Upload JSR package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: jsr_package path: | @@ -150,13 +150,13 @@ jobs: needs: [codegen, build-typescript] steps: - name: Download NPM package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: npm_package path: npm_package - name: Download JSR package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: jsr_package path: jsr_package @@ -166,7 +166,7 @@ jobs: cd npm_package && zip -r ../meshtastic-protobufs-npm.zip . && cd .. cd jsr_package && zip -r ../meshtastic-protobufs-jsr.zip . && cd .. - name: Upload release zips - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: release_zips path: | @@ -178,7 +178,7 @@ jobs: if: ${{ !inputs.dry_run }} steps: - name: Download release zips - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: release_zips @@ -213,7 +213,7 @@ jobs: if: ${{ !inputs.dry_run }} steps: - name: Download NPM package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: npm_package @@ -237,7 +237,7 @@ jobs: id-token: write steps: - name: Download JSR package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: jsr_package From f482e35fcb998b9a768b82527b88961f47927f58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:37:05 -0500 Subject: [PATCH 30/52] Update dependency typescript to v7 (#1008) --- packages/ts/deno.lock | 504 ++++++++++++++++++++++++++++++++++++++- packages/ts/package.json | 2 +- 2 files changed, 502 insertions(+), 4 deletions(-) diff --git a/packages/ts/deno.lock b/packages/ts/deno.lock index d39f28e79..85f02d964 100644 --- a/packages/ts/deno.lock +++ b/packages/ts/deno.lock @@ -1,16 +1,514 @@ { - "version": "4", + "version": "5", "specifiers": { - "npm:@bufbuild/protobuf@^2.2.3": "2.2.3" + "npm:@bufbuild/protobuf@^2.2.3": "2.2.3", + "npm:tsdown@~0.13.4": "0.13.5_typescript@7.0.2", + "npm:typescript@7": "7.0.2" }, "npm": { + "@babel/generator@7.29.7": { + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dependencies": [ + "@babel/parser", + "@babel/types", + "@jridgewell/gen-mapping", + "@jridgewell/trace-mapping", + "jsesc" + ] + }, + "@babel/helper-string-parser@7.29.7": { + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==" + }, + "@babel/helper-validator-identifier@7.29.7": { + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==" + }, + "@babel/parser@7.29.7": { + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dependencies": [ + "@babel/types" + ], + "bin": true + }, + "@babel/types@7.29.7": { + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dependencies": [ + "@babel/helper-string-parser", + "@babel/helper-validator-identifier" + ] + }, "@bufbuild/protobuf@2.2.3": { "integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==" + }, + "@emnapi/core@1.11.2": { + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "dependencies": [ + "@emnapi/wasi-threads", + "tslib" + ] + }, + "@emnapi/runtime@1.11.2": { + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dependencies": [ + "tslib" + ] + }, + "@emnapi/wasi-threads@1.2.2": { + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dependencies": [ + "tslib" + ] + }, + "@jridgewell/gen-mapping@0.3.13": { + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dependencies": [ + "@jridgewell/sourcemap-codec", + "@jridgewell/trace-mapping" + ] + }, + "@jridgewell/resolve-uri@3.1.2": { + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" + }, + "@jridgewell/sourcemap-codec@1.5.5": { + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "@jridgewell/trace-mapping@0.3.31": { + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dependencies": [ + "@jridgewell/resolve-uri", + "@jridgewell/sourcemap-codec" + ] + }, + "@napi-rs/wasm-runtime@1.1.6_@emnapi+core@1.11.2_@emnapi+runtime@1.11.2": { + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dependencies": [ + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util" + ] + }, + "@oxc-project/types@0.140.0": { + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==" + }, + "@quansync/fs@1.0.0": { + "integrity": "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==", + "dependencies": [ + "quansync" + ] + }, + "@rolldown/binding-android-arm64@1.2.0": { + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@rolldown/binding-darwin-arm64@1.2.0": { + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@rolldown/binding-darwin-x64@1.2.0": { + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@rolldown/binding-freebsd-x64@1.2.0": { + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@rolldown/binding-linux-arm-gnueabihf@1.2.0": { + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@rolldown/binding-linux-arm64-gnu@1.2.0": { + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rolldown/binding-linux-arm64-musl@1.2.0": { + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rolldown/binding-linux-ppc64-gnu@1.2.0": { + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@rolldown/binding-linux-s390x-gnu@1.2.0": { + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@rolldown/binding-linux-x64-gnu@1.2.0": { + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rolldown/binding-linux-x64-musl@1.2.0": { + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rolldown/binding-openharmony-arm64@1.2.0": { + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@rolldown/binding-wasm32-wasi@1.2.0": { + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", + "dependencies": [ + "@emnapi/core", + "@emnapi/runtime", + "@napi-rs/wasm-runtime" + ], + "cpu": ["wasm32"] + }, + "@rolldown/binding-win32-arm64-msvc@1.2.0": { + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@rolldown/binding-win32-x64-msvc@1.2.0": { + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@rolldown/pluginutils@1.0.1": { + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==" + }, + "@tybys/wasm-util@0.10.3": { + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dependencies": [ + "tslib" + ] + }, + "@typescript/typescript-aix-ppc64@7.0.2": { + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@typescript/typescript-darwin-arm64@7.0.2": { + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@typescript/typescript-darwin-x64@7.0.2": { + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@typescript/typescript-freebsd-arm64@7.0.2": { + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@typescript/typescript-freebsd-x64@7.0.2": { + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@typescript/typescript-linux-arm64@7.0.2": { + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@typescript/typescript-linux-arm@7.0.2": { + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@typescript/typescript-linux-loong64@7.0.2": { + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@typescript/typescript-linux-mips64el@7.0.2": { + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@typescript/typescript-linux-ppc64@7.0.2": { + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@typescript/typescript-linux-riscv64@7.0.2": { + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@typescript/typescript-linux-s390x@7.0.2": { + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@typescript/typescript-linux-x64@7.0.2": { + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@typescript/typescript-netbsd-arm64@7.0.2": { + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@typescript/typescript-netbsd-x64@7.0.2": { + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@typescript/typescript-openbsd-arm64@7.0.2": { + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@typescript/typescript-openbsd-x64@7.0.2": { + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@typescript/typescript-sunos-x64@7.0.2": { + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@typescript/typescript-win32-arm64@7.0.2": { + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@typescript/typescript-win32-x64@7.0.2": { + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "os": ["win32"], + "cpu": ["x64"] + }, + "ansis@4.3.1": { + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==" + }, + "ast-kit@2.2.0": { + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "dependencies": [ + "@babel/parser", + "pathe" + ] + }, + "birpc@2.9.0": { + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==" + }, + "cac@6.7.14": { + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==" + }, + "chokidar@4.0.3": { + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dependencies": [ + "readdirp" + ] + }, + "debug@4.4.3": { + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dependencies": [ + "ms" + ] + }, + "defu@6.1.7": { + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==" + }, + "diff@8.0.4": { + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==" + }, + "dts-resolver@2.1.3": { + "integrity": "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==" + }, + "empathic@2.0.1": { + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==" + }, + "fdir@6.5.0_picomatch@4.0.5": { + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dependencies": [ + "picomatch" + ], + "optionalPeers": [ + "picomatch" + ] + }, + "get-tsconfig@4.14.0": { + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dependencies": [ + "resolve-pkg-maps" + ] + }, + "hookable@5.5.3": { + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + }, + "jiti@2.7.0": { + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "bin": true + }, + "jsesc@3.1.0": { + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": true + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "pathe@2.0.3": { + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, + "picomatch@4.0.5": { + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==" + }, + "quansync@1.0.0": { + "integrity": "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==" + }, + "readdirp@4.1.2": { + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" + }, + "resolve-pkg-maps@1.0.0": { + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, + "rolldown-plugin-dts@0.15.10_rolldown@1.2.0_typescript@7.0.2": { + "integrity": "sha512-8cPVAVQUo9tYAoEpc3jFV9RxSil13hrRRg8cHC9gLXxRMNtWPc1LNMSDXzjyD+5Vny49sDZH77JlXp/vlc4I3g==", + "dependencies": [ + "@babel/generator", + "@babel/parser", + "@babel/types", + "ast-kit", + "birpc", + "debug", + "dts-resolver", + "get-tsconfig", + "rolldown", + "typescript" + ], + "optionalPeers": [ + "typescript" + ] + }, + "rolldown@1.2.0": { + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", + "dependencies": [ + "@oxc-project/types", + "@rolldown/pluginutils" + ], + "optionalDependencies": [ + "@rolldown/binding-android-arm64", + "@rolldown/binding-darwin-arm64", + "@rolldown/binding-darwin-x64", + "@rolldown/binding-freebsd-x64", + "@rolldown/binding-linux-arm-gnueabihf", + "@rolldown/binding-linux-arm64-gnu", + "@rolldown/binding-linux-arm64-musl", + "@rolldown/binding-linux-ppc64-gnu", + "@rolldown/binding-linux-s390x-gnu", + "@rolldown/binding-linux-x64-gnu", + "@rolldown/binding-linux-x64-musl", + "@rolldown/binding-openharmony-arm64", + "@rolldown/binding-wasm32-wasi", + "@rolldown/binding-win32-arm64-msvc", + "@rolldown/binding-win32-x64-msvc" + ], + "bin": true + }, + "semver@7.8.5": { + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "bin": true + }, + "tinyexec@1.2.4": { + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==" + }, + "tinyglobby@0.2.17": { + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dependencies": [ + "fdir", + "picomatch" + ] + }, + "tree-kill@1.2.2": { + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": true + }, + "tsdown@0.13.5_typescript@7.0.2": { + "integrity": "sha512-lagBtBSdm1yWBFvAbg3+a2/x7eRNqsf5fv34doXXOGnxRIBlfzYCEVfK6cwOgkTNhORMhdWvaqtXZV3h2x1ojQ==", + "dependencies": [ + "ansis", + "cac", + "chokidar", + "debug", + "diff", + "empathic", + "hookable", + "rolldown", + "rolldown-plugin-dts", + "semver", + "tinyexec", + "tinyglobby", + "tree-kill", + "typescript", + "unconfig" + ], + "optionalPeers": [ + "typescript" + ], + "bin": true + }, + "tslib@2.8.1": { + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "typescript@7.0.2": { + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "optionalDependencies": [ + "@typescript/typescript-aix-ppc64", + "@typescript/typescript-darwin-arm64", + "@typescript/typescript-darwin-x64", + "@typescript/typescript-freebsd-arm64", + "@typescript/typescript-freebsd-x64", + "@typescript/typescript-linux-arm", + "@typescript/typescript-linux-arm64", + "@typescript/typescript-linux-loong64", + "@typescript/typescript-linux-mips64el", + "@typescript/typescript-linux-ppc64", + "@typescript/typescript-linux-riscv64", + "@typescript/typescript-linux-s390x", + "@typescript/typescript-linux-x64", + "@typescript/typescript-netbsd-arm64", + "@typescript/typescript-netbsd-x64", + "@typescript/typescript-openbsd-arm64", + "@typescript/typescript-openbsd-x64", + "@typescript/typescript-sunos-x64", + "@typescript/typescript-win32-arm64", + "@typescript/typescript-win32-x64" + ], + "bin": true + }, + "unconfig-core@7.5.0": { + "integrity": "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==", + "dependencies": [ + "@quansync/fs", + "quansync" + ] + }, + "unconfig@7.5.0": { + "integrity": "sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==", + "dependencies": [ + "@quansync/fs", + "defu", + "jiti", + "quansync", + "unconfig-core" + ] } }, "workspace": { "dependencies": [ "npm:@bufbuild/protobuf@^2.2.3" - ] + ], + "packageJson": { + "dependencies": [ + "npm:@bufbuild/protobuf@^2.2.3", + "npm:tsdown@~0.13.4", + "npm:typescript@7" + ] + } } } diff --git a/packages/ts/package.json b/packages/ts/package.json index d99aeb865..40cb09319 100755 --- a/packages/ts/package.json +++ b/packages/ts/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "tsdown": "^0.13.4", - "typescript": "^5.8.3" + "typescript": "^7.0.0" }, "scripts": { "build": "tsdown" From 52a265c52aa3136ee327c6fcfb8a92a80c2873ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:37:31 -0500 Subject: [PATCH 31/52] Update android-actions/setup-android action to v4 (#1007) --- .github/workflows/kmp-pull-request.yml | 2 +- .github/workflows/publish-kmp.yml | 4 ++-- .github/workflows/snapshot-kmp.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/kmp-pull-request.yml b/.github/workflows/kmp-pull-request.yml index ff84c6ad0..a1167f5b2 100644 --- a/.github/workflows/kmp-pull-request.yml +++ b/.github/workflows/kmp-pull-request.yml @@ -24,7 +24,7 @@ jobs: java-version: "21" - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index add6dd9bc..70836298f 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -54,7 +54,7 @@ jobs: java-version: "21" - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 @@ -82,7 +82,7 @@ jobs: java-version: "21" - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index 42c1db5fa..332f3d426 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -31,7 +31,7 @@ jobs: java-version: "21" - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 From 4c30ebd81574018505a053f11a70812aabf3a552 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:37:50 -0500 Subject: [PATCH 32/52] Update actions/checkout action to v7 (#1004) --- .github/workflows/create_tag.yml | 2 +- .github/workflows/kmp-pull-request.yml | 2 +- .github/workflows/publish-kmp.yml | 4 ++-- .github/workflows/publish.yml | 4 ++-- .github/workflows/pull_request.yml | 2 +- .github/workflows/schema-registry.yml | 2 +- .github/workflows/snapshot-kmp.yml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index b0823c335..ba4a800d6 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 - id: version diff --git a/.github/workflows/kmp-pull-request.yml b/.github/workflows/kmp-pull-request.yml index a1167f5b2..81960adcc 100644 --- a/.github/workflows/kmp-pull-request.yml +++ b/.github/workflows/kmp-pull-request.yml @@ -15,7 +15,7 @@ jobs: runs-on: macos-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup Java uses: actions/setup-java@v4 diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index 70836298f..7f664668c 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -27,7 +27,7 @@ jobs: tag: ${{ steps.version.outputs.TAG }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -71,7 +71,7 @@ jobs: if: ${{ !inputs.dry_run }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d40e8cdb0..5827b11e1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -28,7 +28,7 @@ jobs: tag: ${{ steps.version.outputs.TAG }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -195,7 +195,7 @@ jobs: if: ${{ !inputs.dry_run }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup Buf uses: bufbuild/buf-setup-action@v1.50.0 diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index dbf4bedf4..8ebf57bf5 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Buf PR Checks uses: bufbuild/buf-action@v1.4.0 diff --git a/.github/workflows/schema-registry.yml b/.github/workflows/schema-registry.yml index ab578a9a0..57bccc7e8 100644 --- a/.github/workflows/schema-registry.yml +++ b/.github/workflows/schema-registry.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Push to schema registry uses: bufbuild/buf-action@v1.4.0 diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index 332f3d426..a4217d335 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -20,7 +20,7 @@ jobs: runs-on: macos-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 From 1cd820cfb6bff0a3c6c9d6a5ab083e9d3cdef18c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:38:09 -0500 Subject: [PATCH 33/52] Update actions/setup-java action to v5 (#1005) --- .github/workflows/kmp-pull-request.yml | 2 +- .github/workflows/publish-kmp.yml | 4 ++-- .github/workflows/snapshot-kmp.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/kmp-pull-request.yml b/.github/workflows/kmp-pull-request.yml index 81960adcc..43a39fd2b 100644 --- a/.github/workflows/kmp-pull-request.yml +++ b/.github/workflows/kmp-pull-request.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v7 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: "21" diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index 7f664668c..0fb9dde90 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -48,7 +48,7 @@ jobs: echo "TAG=$TAG" >> "$GITHUB_OUTPUT" - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: "21" @@ -76,7 +76,7 @@ jobs: fetch-depth: 0 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: "21" diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index a4217d335..a146c582f 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -25,7 +25,7 @@ jobs: fetch-depth: 0 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: "21" From b73e5ad2b2371fece6432e2de135073599482b25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:38:28 -0500 Subject: [PATCH 34/52] Update actions/setup-node action to v7 (#1006) --- .github/workflows/publish.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5827b11e1..6cf32ef46 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -111,7 +111,7 @@ jobs: echo "=== lib/ contents ===" ls -la lib/ || echo "lib folder not found" - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: "24" @@ -218,7 +218,7 @@ jobs: name: npm_package - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: "24" registry-url: "https://registry.npmjs.org" @@ -242,7 +242,7 @@ jobs: name: jsr_package - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: "24" From 0d983b8b99cc0c91284fd0797da52db746f87dee Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 21 Jul 2026 07:52:52 -0500 Subject: [PATCH 35/52] ci: auto-publish every package when a release tag is cut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create_tag.yml creates the release tag with GITHUB_TOKEN, and GitHub's recursion guard means a GITHUB_TOKEN-pushed tag does NOT fire the `push: tags` trigger on publish.yml / publish-kmp.yml. Publishing has therefore depended on someone manually dispatching each publish workflow after every release — and when that is missed, an artifact silently lags its own tag. Concretely: org.meshtastic:protobufs (the KMP artifact) sat at 2.7.25 while v2.7.26 was tagged a month ago; the npm package was hand-dispatched to 2.7.26 but the KMP one was not. Wire the release flow directly instead of relying on the dead tag trigger: - Add a `workflow_call` trigger to publish.yml and publish-kmp.yml (their version/dry_run logic already reads `inputs.*`, so no job changes are needed — workflow_call populates the same inputs). - create_tag.yml now calls both publishers via `uses:` after cutting the tag, passing the new version and `secrets: inherit`. - Grant `id-token: write` at the create_tag level: a reusable workflow cannot exceed the caller's token scope, and publish.yml needs it for JSR OIDC / npm provenance. The existing `push: tags` and `workflow_dispatch` triggers are kept, so manual dispatch and any future PAT-pushed tags still work; the dead push trigger simply never fires in the current flow. Co-Authored-By: Claude Fable 5 Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> --- .github/workflows/create_tag.yml | 28 ++++++++++++++++++++++++++++ .github/workflows/publish-kmp.yml | 14 ++++++++++++++ .github/workflows/publish.yml | 14 ++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index ba4a800d6..585a757e8 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -1,7 +1,12 @@ name: Create tag +# contents: write — create the release/tag (increment_version). +# id-token: write — required by the called publish.yml for JSR OIDC / npm +# provenance. A reusable workflow cannot exceed the caller's token scope, +# so it must be granted here even though create_tag itself doesn't use it. permissions: contents: write + id-token: write on: workflow_dispatch: @@ -18,6 +23,8 @@ on: jobs: increment_version: runs-on: ubuntu-latest + outputs: + new_version: ${{ steps.version.outputs.NEW_VERSION }} steps: - name: Checkout code @@ -70,3 +77,24 @@ jobs: BUF_TOKEN: ${{ secrets.BUF_TOKEN }} run: | buf push --tag ${{ steps.version.outputs.NEW_VERSION }} + + # The tag above is created with GITHUB_TOKEN, which by design does NOT fire + # the `push: tags` trigger on the publish workflows (GitHub's recursion + # guard). Before this, publishing depended on someone manually dispatching + # each publish workflow — and when that was missed, an artifact silently + # lagged its tag (org.meshtastic:protobufs sat at 2.7.25 while v2.7.26 was + # tagged). Invoke the publishers directly instead so every tag publishes + # every package. + publish-npm: + needs: increment_version + uses: ./.github/workflows/publish.yml + with: + version: ${{ needs.increment_version.outputs.new_version }} + secrets: inherit + + publish-kmp: + needs: increment_version + uses: ./.github/workflows/publish-kmp.yml + with: + version: ${{ needs.increment_version.outputs.new_version }} + secrets: inherit diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index 0fb9dde90..53085ad5d 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -15,6 +15,20 @@ on: required: false type: boolean default: false + # Called by create_tag.yml right after a release tag is cut. Tags created + # with GITHUB_TOKEN do not fire the `push: tags` trigger above (GitHub's + # recursion guard), so the release flow invokes this workflow directly. + workflow_call: + inputs: + version: + description: "Version to publish (e.g. v1.2.3)." + required: true + type: string + dry_run: + description: "Dry run mode - build and publish to Maven Local only" + required: false + type: boolean + default: false permissions: contents: read diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6cf32ef46..b0b6663a9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,6 +15,20 @@ on: required: false type: boolean default: false + # Called by create_tag.yml right after a release tag is cut. Tags created + # with GITHUB_TOKEN do not fire the `push: tags` trigger above (GitHub's + # recursion guard), so the release flow invokes this workflow directly. + workflow_call: + inputs: + version: + description: "Version to publish (e.g. v1.2.3)." + required: true + type: string + dry_run: + description: "Dry run mode - generate artifacts without publishing" + required: false + type: boolean + default: false permissions: contents: write From e03a36c455a1d69baa0942e9bd2bccfda04b1972 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 21 Jul 2026 08:12:59 -0500 Subject: [PATCH 36/52] ci: address CodeRabbit review on the auto-publish wiring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Least-privilege permissions: default the workflow to contents: read and grant writes per-job — contents: write to increment_version (release+tag), contents+id-token: write to the publish-npm caller, contents: read to publish-kmp. (A job that calls a reusable workflow can scope its own permissions, so the broad workflow-level grant was unnecessary.) - Remove the Buf schema-registry push from increment_version: now that create_tag invokes publish.yml, its push-buf-registry job runs the same 'buf push --tag' — keeping it here too pushed the tag twice per release. publish.yml now solely owns the Buf push. Co-Authored-By: Claude Fable 5 Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> --- .github/workflows/create_tag.yml | 33 +++++++++++++------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index 585a757e8..61f682864 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -1,12 +1,8 @@ name: Create tag -# contents: write — create the release/tag (increment_version). -# id-token: write — required by the called publish.yml for JSR OIDC / npm -# provenance. A reusable workflow cannot exceed the caller's token scope, -# so it must be granted here even though create_tag itself doesn't use it. +# Least privilege: default read-only, each job grants only what it needs. permissions: - contents: write - id-token: write + contents: read on: workflow_dispatch: @@ -23,6 +19,8 @@ on: jobs: increment_version: runs-on: ubuntu-latest + permissions: + contents: write # create the release + tag outputs: new_version: ${{ steps.version.outputs.NEW_VERSION }} @@ -64,19 +62,9 @@ jobs: generateReleaseNotes: true token: ${{ github.token }} - - name: Setup Buf - uses: bufbuild/buf-action@v1.4.0 - with: - version: 1.72.0 # renovate: datasource=github-releases depName=bufbuild/buf - github_token: ${{ github.token }} - token: ${{ secrets.BUF_TOKEN }} - setup_only: true - - - name: Push to schema registry - env: - BUF_TOKEN: ${{ secrets.BUF_TOKEN }} - run: | - buf push --tag ${{ steps.version.outputs.NEW_VERSION }} + # The Buf schema-registry push previously lived here. It now runs in + # publish.yml's push-buf-registry job (invoked below), so keeping it + # here too would push the same tag to Buf twice per release. # The tag above is created with GITHUB_TOKEN, which by design does NOT fire # the `push: tags` trigger on the publish workflows (GitHub's recursion @@ -84,9 +72,12 @@ jobs: # each publish workflow — and when that was missed, an artifact silently # lagged its tag (org.meshtastic:protobufs sat at 2.7.25 while v2.7.26 was # tagged). Invoke the publishers directly instead so every tag publishes - # every package. + # every package. publish.yml also owns the Buf schema-registry push. publish-npm: needs: increment_version + permissions: + contents: write # create-release + upload assets + id-token: write # JSR OIDC / npm provenance uses: ./.github/workflows/publish.yml with: version: ${{ needs.increment_version.outputs.new_version }} @@ -94,6 +85,8 @@ jobs: publish-kmp: needs: increment_version + permissions: + contents: read uses: ./.github/workflows/publish-kmp.yml with: version: ${{ needs.increment_version.outputs.new_version }} From 2e977cf792adf1d2f6cb4c89b33eb08484492d59 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:52:32 -0500 Subject: [PATCH 37/52] docs: fix broken CI badge in README The root README CI badge pointed at a nonexistent workflow (ci.yml), so it rendered as an error. Point it at the repo's actual PR workflow (pull_request.yml). Release-trigger automation for the KMP/npm/JSR publishers is handled separately in #1014. Co-Authored-By: Claude Opus 4.8 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2c266426..7de787ba6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Meshtastic Protobuf Definitions -[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/protobufs/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/protobufs/actions/workflows/ci.yml) +[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/protobufs/pull_request.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/protobufs/actions/workflows/pull_request.yml) [![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/protobufs)](https://cla-assistant.io/meshtastic/protobufs) [![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/) [![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss) From 06f6265d9ba46d3f9cdd95d80b269bff6ff1a953 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 21 Jul 2026 13:43:38 -0500 Subject: [PATCH 38/52] ci(kmp): add remote HTTP build cache and Konan toolchain caching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add packages/kmp/gradle/build-cache.settings.gradle (shared remote HTTP build cache), applied from packages/kmp/settings.gradle.kts and configured from the GRADLE_CACHE_URL / GRADLE_CACHE_USERNAME / GRADLE_CACHE_PASSWORD secrets. Push is enabled only when credentials are present, so fork PRs are pull-only and cannot poison the cache. - Pass GRADLE_CACHE_* to the KMP CI, snapshot, and publish workflows. - Cache ~/.konan across those workflows — each compiles all 14 KMP targets (including native) on macOS from a cold Konan today. Part of the Meshtastic KMP library standard alignment (CI caching). Co-Authored-By: Claude Opus 4.8 --- .github/workflows/kmp-pull-request.yml | 13 +++++ .github/workflows/publish-kmp.yml | 21 +++++++ .github/workflows/snapshot-kmp.yml | 13 +++++ .../kmp/gradle/build-cache.settings.gradle | 56 +++++++++++++++++++ packages/kmp/settings.gradle.kts | 2 + 5 files changed, 105 insertions(+) create mode 100644 packages/kmp/gradle/build-cache.settings.gradle diff --git a/.github/workflows/kmp-pull-request.yml b/.github/workflows/kmp-pull-request.yml index 43a39fd2b..7b800c78c 100644 --- a/.github/workflows/kmp-pull-request.yml +++ b/.github/workflows/kmp-pull-request.yml @@ -10,6 +10,11 @@ on: permissions: contents: read +env: + GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} + GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} + GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + jobs: build-kmp: runs-on: macos-latest @@ -29,5 +34,13 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 + - name: Cache Konan (Kotlin/Native toolchain) + uses: actions/cache@v6 + with: + path: ~/.konan + key: konan-${{ runner.os }}-${{ hashFiles('packages/kmp/build.gradle.kts', 'packages/kmp/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + konan-${{ runner.os }}- + - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp build -PVERSION_NAME=0.0.0-pr diff --git a/.github/workflows/publish-kmp.yml b/.github/workflows/publish-kmp.yml index 0fb9dde90..1357e5400 100644 --- a/.github/workflows/publish-kmp.yml +++ b/.github/workflows/publish-kmp.yml @@ -19,6 +19,11 @@ on: permissions: contents: read +env: + GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} + GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} + GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + jobs: build-kmp: runs-on: macos-latest @@ -59,6 +64,14 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 + - name: Cache Konan (Kotlin/Native toolchain) + uses: actions/cache@v6 + with: + path: ~/.konan + key: konan-${{ runner.os }}-${{ hashFiles('packages/kmp/build.gradle.kts', 'packages/kmp/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + konan-${{ runner.os }}- + - name: Build KMP package run: packages/kmp/gradlew --no-daemon -p packages/kmp clean build -PVERSION_NAME=${{ steps.version.outputs.VERSION }} @@ -87,6 +100,14 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 + - name: Cache Konan (Kotlin/Native toolchain) + uses: actions/cache@v6 + with: + path: ~/.konan + key: konan-${{ runner.os }}-${{ hashFiles('packages/kmp/build.gradle.kts', 'packages/kmp/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + konan-${{ runner.os }}- + - name: Publish to Maven Central env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} diff --git a/.github/workflows/snapshot-kmp.yml b/.github/workflows/snapshot-kmp.yml index a146c582f..1b92a8f28 100644 --- a/.github/workflows/snapshot-kmp.yml +++ b/.github/workflows/snapshot-kmp.yml @@ -15,6 +15,11 @@ on: permissions: contents: read +env: + GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} + GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} + GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + jobs: publish-snapshot: runs-on: macos-latest @@ -36,6 +41,14 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 + - name: Cache Konan (Kotlin/Native toolchain) + uses: actions/cache@v6 + with: + path: ~/.konan + key: konan-${{ runner.os }}-${{ hashFiles('packages/kmp/build.gradle.kts', 'packages/kmp/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + konan-${{ runner.os }}- + - name: Set version name run: | # Name the snapshot after the latest tag (v-stripped), the commit count diff --git a/packages/kmp/gradle/build-cache.settings.gradle b/packages/kmp/gradle/build-cache.settings.gradle new file mode 100644 index 000000000..824417e0f --- /dev/null +++ b/packages/kmp/gradle/build-cache.settings.gradle @@ -0,0 +1,56 @@ +/* + * Shared remote HTTP Gradle build cache for Meshtastic KMP libraries. + * + * Credentials come from the GRADLE_CACHE_URL / GRADLE_CACHE_USERNAME / + * GRADLE_CACHE_PASSWORD environment variables (CI secrets), or a + * local.properties / config.properties entry for local use. Push is enabled + * only when credentials are present, so fork PRs (which have no secrets) are + * pull-only and cannot poison the cache. + */ + +def getMeshProperty(String key) { + def env = System.getenv(key) + if (env) return env + def currentDir = settingsDir + while (currentDir != null) { + for (name in ["local.properties", "config.properties"]) { + def f = new File(currentDir, name) + if (f.exists()) { + def props = new Properties() + f.withInputStream { props.load(it) } + if (props.containsKey(key)) return props.getProperty(key) + } + } + currentDir = currentDir.parentFile + } + return null +} + +buildCache { + local { + enabled = true + } + remote(HttpBuildCache) { + // Some cache servers return 403 on "Expect: 100-continue". + useExpectContinue = false + def cacheUrl = getMeshProperty("GRADLE_CACHE_URL")?.trim() + def cacheUsername = getMeshProperty("GRADLE_CACHE_USERNAME")?.trim() + def cachePassword = getMeshProperty("GRADLE_CACHE_PASSWORD")?.trim() + if (cacheUrl) { + url = cacheUrl.endsWith("/") ? cacheUrl : "${cacheUrl}/" + if (cacheUsername && cachePassword) { + credentials { + username = cacheUsername + password = cachePassword + } + } + allowInsecureProtocol = true + allowUntrustedServer = true + // Push only when credentials exist -> fork PRs are pull-only. + push = (cacheUsername && cachePassword) + enabled = true + } else { + enabled = false + } + } +} diff --git a/packages/kmp/settings.gradle.kts b/packages/kmp/settings.gradle.kts index 89b3f9e74..6fb5e07b2 100644 --- a/packages/kmp/settings.gradle.kts +++ b/packages/kmp/settings.gradle.kts @@ -13,4 +13,6 @@ dependencyResolutionManagement { } } +apply(from = "gradle/build-cache.settings.gradle") + rootProject.name = "protobufs" From f92ce54b21377362b23eff09da53f07a2e4e8ad5 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:53:35 -0500 Subject: [PATCH 39/52] ci: harden shared build cache (TLS-only, trusted-event pushes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses CodeRabbit review of the shared build-cache script: - Drop allowInsecureProtocol/allowUntrustedServer — the cache server presents a valid public TLS cert, so enforce HTTPS + certificate validation. - Write to the cache only on trusted events (push/merge_group/local) with credentials present, so pull_request runs stay pull-only and cannot poison the cache. Co-Authored-By: Claude Opus 4.8 --- .../kmp/gradle/build-cache.settings.gradle | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/kmp/gradle/build-cache.settings.gradle b/packages/kmp/gradle/build-cache.settings.gradle index 824417e0f..dd9bfc87b 100644 --- a/packages/kmp/gradle/build-cache.settings.gradle +++ b/packages/kmp/gradle/build-cache.settings.gradle @@ -3,9 +3,10 @@ * * Credentials come from the GRADLE_CACHE_URL / GRADLE_CACHE_USERNAME / * GRADLE_CACHE_PASSWORD environment variables (CI secrets), or a - * local.properties / config.properties entry for local use. Push is enabled - * only when credentials are present, so fork PRs (which have no secrets) are - * pull-only and cannot poison the cache. + * local.properties / config.properties entry for local use. Writes to the + * cache happen only from trusted events (local dev, push, merge_group) with + * credentials present, so pull-request runs (and credential-less fork PRs) + * stay pull-only and cannot poison the cache. */ def getMeshProperty(String key) { @@ -37,6 +38,9 @@ buildCache { def cacheUsername = getMeshProperty("GRADLE_CACHE_USERNAME")?.trim() def cachePassword = getMeshProperty("GRADLE_CACHE_PASSWORD")?.trim() if (cacheUrl) { + // HTTPS + valid TLS enforced (no allowInsecureProtocol / no + // allowUntrustedServer): the cache server must present a trusted + // certificate over TLS. url = cacheUrl.endsWith("/") ? cacheUrl : "${cacheUrl}/" if (cacheUsername && cachePassword) { credentials { @@ -44,10 +48,12 @@ buildCache { password = cachePassword } } - allowInsecureProtocol = true - allowUntrustedServer = true - // Push only when credentials exist -> fork PRs are pull-only. - push = (cacheUsername && cachePassword) + // Write only from trusted events (local dev, push to a protected + // branch, or the merge queue) with credentials — never from + // pull_request runs, so unmerged code can't poison the cache. + def eventName = System.getenv("GITHUB_EVENT_NAME") + def trustedForPush = eventName == null || eventName == "push" || eventName == "merge_group" + push = (cacheUsername && cachePassword && trustedForPush) enabled = true } else { enabled = false From 3fec03bb9bcab07c69f922dbb36c279fd1d335dd Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 28 Jul 2026 11:01:34 +0100 Subject: [PATCH 40/52] Add explicit presence for RSSI: MeshPacket.rx_rssi optional, NodeInfoLite.rssi storage field MeshPacket.rx_rssi was proto3 singular, so an unset value and a genuine 0 dBm reading were byte-identical on the wire (0 is a legal SX126x return, and SX127x's offset+register formula can even go positive). Mark it optional so absence survives encoding, mirroring the precedent already set by NodeInfo.hops_away. NodeInfoLite had no RSSI field at all, so nothing survived a device reboot for replayed history packets to restore - every replay showed RSSI 0 regardless of the real measurement. Add NodeInfoLite.rssi (tag 20, sint32, next free tag) with the same "0 is not automatically unknown" caveat; presence is tracked via NODEINFO_BITFIELD_HAS_RSSI on the firmware side rather than a second wire-level bool, to avoid a RAM cost per stored node. Companion firmware change: meshtastic/firmware, phantom-node-fix-perhaps branch, .notes/plans/plan-executed-snr-rssi-replay-fidelity.md. --- meshtastic/deviceonly.options | 3 +++ meshtastic/deviceonly.proto | 13 ++++++++++++- meshtastic/mesh.proto | 7 ++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/meshtastic/deviceonly.options b/meshtastic/deviceonly.options index 162545704..ece192d48 100644 --- a/meshtastic/deviceonly.options +++ b/meshtastic/deviceonly.options @@ -11,6 +11,9 @@ *NodeInfoLite.channel int_size:8 *NodeInfoLite.hops_away int_size:8 *NodeInfoLite.next_hop int_size:8 +# Real range is roughly -164..+98 (SX127x low-band offset .. positive-RSSI edge case, see +# phantom-zero-hop-direct-nodes bug notes) - int8 can't hold it, int16 comfortably can. +*NodeInfoLite.rssi int_size:16 # Flattened user fields. long_name was 40 on UserLite; trimmed to 25 here so the # slim header gives back ~15 B/node of RAM. Names that exceeded 24 chars on the diff --git a/meshtastic/deviceonly.proto b/meshtastic/deviceonly.proto index ec28b59d4..15d4b0a5e 100644 --- a/meshtastic/deviceonly.proto +++ b/meshtastic/deviceonly.proto @@ -187,10 +187,21 @@ message NodeInfoLite { /* * Q4-encoded SNR: dB × 4, sint32 zigzag. Matches RouteDiscovery convention. - * Encode: snr_q4 = (int32_t)(snr * 4.0f). Decode: snr = snr_q4 / 4.0f. + * Encode: snr_q4 = (int32_t)lroundf(snr * 4.0f). Decode: snr = snr_q4 / 4.0f. * float snr is always zeroed on disk; this field carries all persisted SNR. + * A stored 0 does not by itself mean "unknown" here - see NODEINFO_BITFIELD_HAS_SNR in + * src/mesh/NodeDB.h for the presence bit that disambiguates a genuine 0 dB reading from + * "never measured". */ sint32 snr_q4 = 19; + + /* + * Last received RSSI (dBm) for this node, restored into replayed packets so history sent to + * the phone after a reconnect isn't misrepresented as a live zero-signal reception. A stored + * 0 does not by itself mean "unknown" - RSSI can legitimately read 0 dBm or, on some radios, + * positive. See NODEINFO_BITFIELD_HAS_RSSI in src/mesh/NodeDB.h for the presence bit. + */ + sint32 rssi = 20; } /* diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index b09a15b0a..6ffbdbe7d 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -1848,8 +1848,13 @@ message MeshPacket { /* * rssi of received packet. Only sent to phone for dispay purposes. + * Explicit presence: rssi 0 is a legitimate reading on some radios (SX126x can report exactly + * 0 dBm; SX127x's formula can even go positive), so implicit-presence proto3 made an unset + * value indistinguishable from a measured one. has_rx_rssi disambiguates; a replayed packet + * built from history the device never restored an RSSI for should leave this field absent + * rather than emitting 0. */ - int32 rx_rssi = 12; + optional int32 rx_rssi = 12; /* * Describe if this message is delayed From 94cdec45ae729650d5a1b0cea356cad12747983b Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 28 Jul 2026 14:42:24 +0100 Subject: [PATCH 41/52] remove rssi & improve notes --- meshtastic/deviceonly.options | 3 --- meshtastic/deviceonly.proto | 8 -------- meshtastic/mesh.proto | 10 ++++++---- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/meshtastic/deviceonly.options b/meshtastic/deviceonly.options index ece192d48..162545704 100644 --- a/meshtastic/deviceonly.options +++ b/meshtastic/deviceonly.options @@ -11,9 +11,6 @@ *NodeInfoLite.channel int_size:8 *NodeInfoLite.hops_away int_size:8 *NodeInfoLite.next_hop int_size:8 -# Real range is roughly -164..+98 (SX127x low-band offset .. positive-RSSI edge case, see -# phantom-zero-hop-direct-nodes bug notes) - int8 can't hold it, int16 comfortably can. -*NodeInfoLite.rssi int_size:16 # Flattened user fields. long_name was 40 on UserLite; trimmed to 25 here so the # slim header gives back ~15 B/node of RAM. Names that exceeded 24 chars on the diff --git a/meshtastic/deviceonly.proto b/meshtastic/deviceonly.proto index 15d4b0a5e..7e025c14c 100644 --- a/meshtastic/deviceonly.proto +++ b/meshtastic/deviceonly.proto @@ -194,14 +194,6 @@ message NodeInfoLite { * "never measured". */ sint32 snr_q4 = 19; - - /* - * Last received RSSI (dBm) for this node, restored into replayed packets so history sent to - * the phone after a reconnect isn't misrepresented as a live zero-signal reception. A stored - * 0 does not by itself mean "unknown" - RSSI can legitimately read 0 dBm or, on some radios, - * positive. See NODEINFO_BITFIELD_HAS_RSSI in src/mesh/NodeDB.h for the presence bit. - */ - sint32 rssi = 20; } /* diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 6ffbdbe7d..008cc1f63 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -1849,10 +1849,8 @@ message MeshPacket { /* * rssi of received packet. Only sent to phone for dispay purposes. * Explicit presence: rssi 0 is a legitimate reading on some radios (SX126x can report exactly - * 0 dBm; SX127x's formula can even go positive), so implicit-presence proto3 made an unset - * value indistinguishable from a measured one. has_rx_rssi disambiguates; a replayed packet - * built from history the device never restored an RSSI for should leave this field absent - * rather than emitting 0. + * 0 dBm; SX127x's formula can even go positive). has_rx_rssi disambiguates; a replayed packet + * built from history should leave this field absent rather than emitting 0. */ optional int32 rx_rssi = 12; @@ -1869,6 +1867,10 @@ message MeshPacket { /* * Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header. * When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled. + * hop_start == 0 does not necessarily mean a direct (0-hop) neighbor: firmware prior to 2.3.0 + * never populated this field, so a receiver can only trust hop_start == 0 as genuine once it has + * decoded the packet and confirmed the sender's bitfield is present (added in 2.5.0). Until then, + * or for a sender that never sets that bitfield, treat hop_start == 0 as unknown, not direct. */ uint32 hop_start = 15; From cd290ba246fb5130cb449055248f7e22c15bcafb Mon Sep 17 00:00:00 2001 From: nomdetom Date: Tue, 28 Jul 2026 20:33:30 +0100 Subject: [PATCH 42/52] Add explicit presence for arrival time: MeshPacket.rx_time optional --- meshtastic/mesh.proto | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 008cc1f63..3f71d1152 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -1809,8 +1809,14 @@ message MeshPacket { * Note: this field is _never_ sent on the radio link itself (to save space) Times * are typically not sent over the mesh, but they will be added to any Packet * (chain of SubPacket) sent to the phone (so the phone can know exact time of reception) - */ - fixed32 rx_time = 7; + * Explicit presence: firmware cannot always attach a trustworthy wall-clock timestamp at the + * moment of reception - a node with no GPS and no phone connected yet has no time source at + * all. has_rx_time disambiguates that state from a genuine (if coincidental) 1970-01-01 + * reading. A packet delivered with this field absent may still be re-timestamped once a valid + * clock becomes available, before the phone ever sees it - "absent" is not guaranteed + * permanent, only "not yet known at last observation". + */ + optional fixed32 rx_time = 7; /* * *Never* sent over the radio links. From 6f21d0caf0fd6897da7b9d709460c6083c96d8ac Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Tue, 11 Aug 2026 09:59:52 +0200 Subject: [PATCH 43/52] Move ADC values to env telemetry (#877) * Move ADC values to environment telemetry * Rename to adc_voltage to avoid confusion * Mark some ADS fields and SHTs as deprecated * Make a multi-measurement wildcard measurement * Return to unpacked messages, to avoid sending repeated lists with no data * Remove unused wildcard options * Add one-wire bridge config * Update ADC and One-Wire temperature channel numbers * Fix formatting for deprecated one_wire_temperature field * Remove unnecessary newline in telemetry.proto * Don't generate code for this field. --- meshtastic/admin.proto | 12 ++++ meshtastic/telemetry.options | 2 +- meshtastic/telemetry.proto | 132 ++++++++++++++++++++++++++++------- 3 files changed, 119 insertions(+), 27 deletions(-) diff --git a/meshtastic/admin.proto b/meshtastic/admin.proto index d120a2c6d..27eb065c4 100644 --- a/meshtastic/admin.proto +++ b/meshtastic/admin.proto @@ -804,6 +804,11 @@ message SensorConfig { * SHTXX temperature and relative humidity sensor configuration */ SHTXX_config shtxx_config = 4; + + /* + * DS248X-800 temperature sensor configuration + */ + DS248X_config ds248x_config = 5; } message SCD4X_config { @@ -893,3 +898,10 @@ message SHTXX_config { */ optional uint32 set_accuracy = 1; } + +message DS248X_config { + /* + * Main channel for temperature reporting (0-7) + */ + optional uint32 main_temperature_channel = 1; +} diff --git a/meshtastic/telemetry.options b/meshtastic/telemetry.options index 5db1af548..fcc657734 100644 --- a/meshtastic/telemetry.options +++ b/meshtastic/telemetry.options @@ -4,7 +4,7 @@ *EnvironmentMetrics.iaq int_size:16 *EnvironmentMetrics.wind_direction int_size:16 *EnvironmentMetrics.soil_moisture int_size:8 -*EnvironmentMetrics.one_wire_temperature max_count:8 +*EnvironmentMetrics.one_wire_temperature type:FT_IGNORE *LocalStats.num_online_nodes int_size:16 *LocalStats.num_total_nodes int_size:16 diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index 53b1bedfb..35465dd28 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -155,9 +155,89 @@ message EnvironmentMetrics { optional float soil_temperature = 22; /* - * One-wire temperature (*C) + * Never implemented, but Voltage may be mis-interpreted by old clients as temperature */ - repeated float one_wire_temperature = 23; + repeated float one_wire_temperature = 23 [deprecated = true]; + + /* + * Multi-channel ADC Voltage Channel 0 (V) + */ + optional float adc_voltage_ch0 = 24; + + /* + * Multi-channel ADC Voltage Channel 1 (V) + */ + optional float adc_voltage_ch1 = 25; + + /* + * Multi-channel ADC Voltage Channel 2 (V) + */ + optional float adc_voltage_ch2 = 26; + + /* + * Multi-channel ADC Voltage Channel 3 (V) + */ + optional float adc_voltage_ch3 = 27; + + /* + * Multi-channel ADC Voltage Channel 4 (V) + */ + optional float adc_voltage_ch4 = 28; + + /* + * Multi-channel ADC Voltage Channel 5 (V) + */ + optional float adc_voltage_ch5 = 29; + + /* + * Multi-channel ADC Voltage Channel 6 (V) + */ + optional float adc_voltage_ch6 = 30; + + /* + * Multi-channel ADC Voltage Channel 7 (V) + */ + optional float adc_voltage_ch7 = 31; + + /* + * Multi-channel One-Wire Temperature Channel 0 (*C) + */ + optional float one_wire_temperature_ch0 = 32; + + /* + * Multi-channel One-Wire Temperature Channel 1 (*C) + */ + optional float one_wire_temperature_ch1 = 33; + + /* + * Multi-channel One-Wire Temperature Channel 2 (*C) + */ + optional float one_wire_temperature_ch2 = 34; + + /* + * Multi-channel One-Wire Temperature Channel 3 (*C) + */ + optional float one_wire_temperature_ch3 = 35; + + /* + * Multi-channel One-Wire Temperature Channel 4 (*C) + */ + optional float one_wire_temperature_ch4 = 36; + + /* + * Multi-channel One-Wire Temperature Channel 5 (*C) + */ + optional float one_wire_temperature_ch5 = 37; + + /* + * Multi-channel One-Wire Temperature Channel 6 (*C) + */ + optional float one_wire_temperature_ch6 = 38; + + /* + * Multi-channel One-Wire Temperature Channel 7 (*C) + */ + optional float one_wire_temperature_ch7 = 39; } /* @@ -195,54 +275,54 @@ message PowerMetrics { optional float ch3_current = 6; /* - * Voltage (Ch4) + * Voltage (Ch4) - TODO Remove */ - optional float ch4_voltage = 7; + optional float ch4_voltage = 7 [deprecated = true]; /* - * Current (Ch4) + * Current (Ch4) - TODO Remove */ - optional float ch4_current = 8; + optional float ch4_current = 8 [deprecated = true]; /* - * Voltage (Ch5) + * Voltage (Ch5) - TODO Remove */ - optional float ch5_voltage = 9; + optional float ch5_voltage = 9 [deprecated = true]; /* - * Current (Ch5) + * Current (Ch5) - TODO Remove */ - optional float ch5_current = 10; + optional float ch5_current = 10 [deprecated = true]; /* - * Voltage (Ch6) + * Voltage (Ch6) - TODO Remove */ - optional float ch6_voltage = 11; + optional float ch6_voltage = 11 [deprecated = true]; /* - * Current (Ch6) + * Current (Ch6) - TODO Remove */ - optional float ch6_current = 12; + optional float ch6_current = 12 [deprecated = true]; /* - * Voltage (Ch7) + * Voltage (Ch7) - TODO Remove */ - optional float ch7_voltage = 13; + optional float ch7_voltage = 13 [deprecated = true]; /* - * Current (Ch7) + * Current (Ch7) - TODO Remove */ - optional float ch7_current = 14; + optional float ch7_current = 14 [deprecated = true]; /* - * Voltage (Ch8) + * Voltage (Ch8) - TODO Remove */ - optional float ch8_voltage = 15; + optional float ch8_voltage = 15 [deprecated = true]; /* - * Current (Ch8) + * Current (Ch8) - TODO Remove */ - optional float ch8_current = 16; + optional float ch8_current = 16 [deprecated = true]; } /* @@ -660,7 +740,7 @@ enum TelemetrySensorType { /* * TODO - REMOVE High accuracy temperature and humidity */ - SHTC3 = 7; + SHTC3 = 7 [deprecated = true]; /* * High accuracy pressure @@ -685,7 +765,7 @@ enum TelemetrySensorType { /* * TODO - REMOVE High accuracy temperature and humidity */ - SHT31 = 12; + SHT31 = 12 [deprecated = true]; /* * PM2.5 air quality sensor @@ -710,7 +790,7 @@ enum TelemetrySensorType { /* * TODO - REMOVE Sensirion High accuracy temperature and humidity */ - SHT4X = 17; + SHT4X = 17 [deprecated = true]; /* * VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. @@ -860,7 +940,7 @@ enum TelemetrySensorType { /* * TODO - REMOVE STH21 Temperature and R. Humidity sensor */ - SHT21 = 47; + SHT21 = 47 [deprecated = true]; /* * Sensirion STC31 CO2 sensor From f3c374d773bf969d3294f2ead1993337c2e07bba Mon Sep 17 00:00:00 2001 From: oscgonfer Date: Tue, 11 Aug 2026 10:39:29 +0200 Subject: [PATCH 44/52] Add SEN6X fields (#1031) * Add SEN6X fields * Address comments * Remove extra whitespace in admin.proto --- meshtastic/admin.proto | 52 ++++++++++++++++++++++++++++++++++++++ meshtastic/telemetry.proto | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/meshtastic/admin.proto b/meshtastic/admin.proto index 27eb065c4..963d3e748 100644 --- a/meshtastic/admin.proto +++ b/meshtastic/admin.proto @@ -809,6 +809,11 @@ message SensorConfig { * DS248X-800 temperature sensor configuration */ DS248X_config ds248x_config = 5; + + /* + * SEN6X PM/RHT/VOC/NOx/CO2/HCHO Sensor configuration + */ + SEN6X_config sen6x_config = 6; } message SCD4X_config { @@ -858,6 +863,53 @@ message SEN5X_config { * One-shot mode (true for low power - one-shot mode, false for normal - continuous mode) */ optional bool set_one_shot_mode = 2; + + /* + * Trigger a fan cleaning cycle + */ + optional bool start_fan_cleaning = 3; +} + +message SEN6X_config { + /* + * Reference temperature in degC + */ + optional float set_temperature = 1; + + /* + * One-shot mode (true for low power - one-shot mode, false for normal - continuous mode) + */ + optional bool set_one_shot_mode = 2; + + /* + * Trigger a fan cleaning cycle + */ + optional bool start_fan_cleaning = 3; + + /* + * Set Automatic self-calibration enabled (CO2-capable variants only: SEN63C, SEN66, SEN69C) + */ + optional bool set_asc = 4; + + /* + * Recalibration target CO2 concentration in ppm (FRC only), CO2-capable variants only + */ + optional uint32 set_target_co2_conc = 5; + + /* + * Altitude of sensor in meters above sea level. 0 - 3000m (overrides ambient pressure), CO2-capable variants only + */ + optional uint32 set_altitude = 6; + + /* + * Sensor ambient pressure in Pa. 70000 - 120000 Pa (overrides altitude), CO2-capable variants only + */ + optional uint32 set_ambient_pressure = 7; + + /* + * Perform a factory reset of the CO2 sensor's calibration, CO2-capable variants only + */ + optional bool factory_reset = 8; } message SCD30_config { diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index 35465dd28..9327fc151 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -453,6 +453,14 @@ message AirQualityMetrics { * Typical Particle Size in um */ optional float particles_tps = 25; + + /* + * Raw PM sensor device status/error register bitmask, as defined by the sensor's own datasheet + * (currently populated by the SEN6X family: bit 4 fan error, bit 6 RH&T error, bit 7 gas/VOC-NOx + * error, bit 9 CO2 error (SEN66), bit 10 HCHO error, bit 11 PM error, bit 12 CO2 error (SEN63C/SEN69C), + * bit 21 fan speed warning) + */ + optional uint32 pm_status_flags = 26; } /* @@ -981,6 +989,11 @@ enum TelemetrySensorType { * HM330X PM SENSOR */ HM330X = 55; + + /* + * Sensirion SEN6X PM/RHT/VOC/NOx/CO2/HCHO sensor family (SEN62, SEN63C, SEN65, SEN66, SEN68, SEN69C) + */ + SEN6X = 56; } /* @@ -999,7 +1012,7 @@ message Nau7802Config { } /* - * SEN5X State, for saving to flash + * SEN5X State, for saving to flash (to be merged with SEN6XState) */ message SEN5XState { /* @@ -1032,3 +1045,38 @@ message SEN5XState { */ optional fixed64 voc_state_array = 6; } + +/* + * SEN6X State, for saving to flash + */ +message SEN6XState { + /* + * Last cleaning time for SEN6X + */ + uint32 last_cleaning_time = 1; + + /* + * Last cleaning time for SEN6X - valid flag + */ + bool last_cleaning_valid = 2; + + /* + * Config flag for one-shot mode (see admin.proto) + */ + bool one_shot_mode = 3; + + /* + * Last VOC state time, for models with a VOC sensor (SEN65, SEN66, SEN68, SEN69C) + */ + optional uint32 voc_state_time = 4; + + /* + * Last VOC state validity flag, for models with a VOC sensor (SEN65, SEN66, SEN68, SEN69C) + */ + optional bool voc_state_valid = 5; + + /* + * VOC state array (8x uint8t), for models with a VOC sensor (SEN65, SEN66, SEN68, SEN69C) + */ + optional fixed64 voc_state_array = 6; +} From b9a02d941086ca7c718b03f5763ad5ef9119853c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 11 Aug 2026 11:54:39 +0200 Subject: [PATCH 45/52] Trim unused DrawnShape.vertices This emits a warning if not removed --- meshtastic/atak.options | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meshtastic/atak.options b/meshtastic/atak.options index 29ec3e109..12e5538bb 100644 --- a/meshtastic/atak.options +++ b/meshtastic/atak.options @@ -44,7 +44,6 @@ # / fill_argb are fixed32 (always 4 bytes on the wire). Vertex pool is 32 # entries x ~12B each ~= 384B worst case. Telestrations beyond 32 vertices # MUST be pre-truncated by the sender with `truncated = true`. -*DrawnShape.vertices max_count:32 *DrawnShape.major_cm int_size:32 *DrawnShape.minor_cm int_size:32 *DrawnShape.angle_deg int_size:16 @@ -107,4 +106,4 @@ *TaskRequest.task_type max_size:12 *TaskRequest.target_uid max_size:32 *TaskRequest.assignee_uid max_size:32 -*TaskRequest.note max_size:48 \ No newline at end of file +*TaskRequest.note max_size:48 From c9cb9ef6ee0dd579fbe9424e232484392637e11e Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Mon, 17 Aug 2026 22:17:19 +0800 Subject: [PATCH 46/52] Add AS3935 lightning sensor telemetry fields (#981) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add AS3935 lightning sensor telemetry fields Adds lightning_strike_count_1h and lightning_distance_km to EnvironmentMetrics (reset on a rolling ~1h window, matching the rainfall_1h precedent), and an AS3935 entry to TelemetrySensorType, to support meshtastic/firmware#10774. Assisted-by: Claude Sonnet 5 Signed-off-by: Andrew Yong * Remove extra newline in telemetry.proto * Add AS3935 tuning capacitance configuration AdminMessage.sensor_config gains AS3935_config with set_tuning_cap_pf, alongside the existing per-sensor configuration messages. AS3935Config holds the trim for saving to flash. The AS3935 does not retain the tuning capacitor across power loss, so firmware stores the value and re-applies it on every boot. --------- Signed-off-by: Andrew Yong Co-authored-by: Thomas Göttgens --- meshtastic/admin.proto | 13 +++++++++++++ meshtastic/telemetry.proto | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/meshtastic/admin.proto b/meshtastic/admin.proto index 963d3e748..0de5779d7 100644 --- a/meshtastic/admin.proto +++ b/meshtastic/admin.proto @@ -814,6 +814,11 @@ message SensorConfig { * SEN6X PM/RHT/VOC/NOx/CO2/HCHO Sensor configuration */ SEN6X_config sen6x_config = 6; + + /* + * AS3935 lightning sensor configuration + */ + AS3935_config as3935_config = 7; } message SCD4X_config { @@ -957,3 +962,11 @@ message DS248X_config { */ optional uint32 main_temperature_channel = 1; } + +message AS3935_config { + /* + * Antenna tuning capacitance in pF, 0 to 120 in steps of 8. The antenna tank must + * resonate within 3.5% of 500kHz; the correct trim is specific to the sensor board. + */ + optional uint32 set_tuning_cap_pf = 1; +} diff --git a/meshtastic/telemetry.proto b/meshtastic/telemetry.proto index 9327fc151..ba0ac625c 100644 --- a/meshtastic/telemetry.proto +++ b/meshtastic/telemetry.proto @@ -238,6 +238,16 @@ message EnvironmentMetrics { * Multi-channel One-Wire Temperature Channel 7 (*C) */ optional float one_wire_temperature_ch7 = 39; + + /* + * Lightning strikes detected in the last hour + */ + optional uint32 lightning_strike_count_1h = 40; + + /* + * Estimated distance to the leading edge of the storm, in km + */ + optional float lightning_distance_km = 41; } /* @@ -994,6 +1004,11 @@ enum TelemetrySensorType { * Sensirion SEN6X PM/RHT/VOC/NOx/CO2/HCHO sensor family (SEN62, SEN63C, SEN65, SEN66, SEN68, SEN69C) */ SEN6X = 56; + + /* + * AS3935 Franklin lightning sensor + */ + AS3935 = 57; } /* @@ -1011,6 +1026,17 @@ message Nau7802Config { float calibrationFactor = 2; } +/* + * AS3935 lightning sensor configuration, for saving to flash + */ +message AS3935Config { + /* + * Antenna tuning capacitance in pF, 0 to 120 in steps of 8. The chip does not retain + * this across power loss, so it is stored here and re-applied on every boot. + */ + uint32 tuning_cap_pf = 1; +} + /* * SEN5X State, for saving to flash (to be merged with SEN6XState) */ From 49d0bc97e4aa875c0564fdfbc086af7083983c45 Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Tue, 18 Aug 2026 09:07:34 -0400 Subject: [PATCH 47/52] Add new firmware editions for Dragon Con and CCC events --- meshtastic/mesh.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 3f71d1152..28b5d5d59 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -2185,6 +2185,16 @@ enum FirmwareEdition { */ FAB = 20; + /* + * Dragon Con, the yearly pop culture convention in Atlanta, GA + */ + DRAGON_CON = 21; + + /* + * Chaos Communication Congress, the hacker conference held yearly in Germany + */ + CCC = 22; + /* * Placeholder for DIY and unofficial events */ From 86e5a30fb070778188e130831449415a1c32e95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 18 Aug 2026 21:04:15 +0200 Subject: [PATCH 48/52] Add SEEED_WIO_TRACKER_L1_PRO_1W --- meshtastic/mesh.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 28b5d5d59..7895ca80d 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -948,6 +948,11 @@ enum HardwareModel { */ HELTEC_RCC6 = 143; + /* + * Seeed Wio Tracker L1 Pro 1W, nRF52840 + SX1262 with 1 W external PA + */ + SEEED_WIO_TRACKER_L1_PRO_1W = 144; + /* * ------------------------------------------------------------------------------------------------------------------------------------------ * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. From b138a28c2749b3dc8a697cd9961cf8bc2a9ea781 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 21 Aug 2026 10:24:47 -0500 Subject: [PATCH 49/52] Add MESHNOLOGY_W12 hardware model Add the Meshnology W12 to the HardwareModel enum. --- meshtastic/mesh.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index bf11c8d3d..5e85e7dfa 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -953,6 +953,11 @@ enum HardwareModel { */ SEEED_WIO_TRACKER_L1_PRO_1W = 144; + /* + * Meshnology W12 + */ + MESHNOLOGY_W12 = 145; + /* * ------------------------------------------------------------------------------------------------------------------------------------------ * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. From 6220d6c91daaa85607b3a14369b86863f4a9fd59 Mon Sep 17 00:00:00 2001 From: Manuel Verch Date: Fri, 21 Aug 2026 12:38:38 -0500 Subject: [PATCH 50/52] Add MESHPAGER_X2 hardware model Add the Seeed Studio MeshPager X2 to the HardwareModel enum. --- meshtastic/mesh.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meshtastic/mesh.proto b/meshtastic/mesh.proto index 5e85e7dfa..1076d1a5f 100644 --- a/meshtastic/mesh.proto +++ b/meshtastic/mesh.proto @@ -958,6 +958,11 @@ enum HardwareModel { */ MESHNOLOGY_W12 = 145; + /* + * Seeed Studio MeshPager X2 + */ + MESHPAGER_X2 = 146; + /* * ------------------------------------------------------------------------------------------------------------------------------------------ * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. From 40c405b570689d7b74f01192e24b60105b1aff35 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 28 Aug 2026 10:18:03 -0500 Subject: [PATCH 51/52] Remove unused beacon broadcast_send_as_node field MeshBeaconConfig.broadcast_send_as_node let a client set a node ID that outgoing beacons would be sent AS, rewriting the packet's `from` field so beacons appeared to originate from another node. Firmware never applied it. The assignment in MeshBeaconModule::sendBeacon() is commented out pending review, so `from` is always the local node number and the field is a settable, persisted no-op: a client can write it, read it back, and see no effect on air. The mechanism was also unsound as designed. Rewriting `from` forges no signature; it only makes isFromUs() false, so Router::perhapsEncode() skips XEdDSA signing and receivers get an unsigned packet attributed to another node. The field never reached a tagged release and has no consumers outside the firmware repo, so it is removed rather than kept. Tag 3 and the field name are reserved to prevent reuse. Co-Authored-By: Claude Opus 5 --- meshtastic/module_config.proto | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 65688697c..e7c6252d9 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -868,14 +868,12 @@ message ModuleConfig { */ uint32 flags = 1; - /* - * Optional: node ID to send beacon messages AS. - * When set, the `from` field of outgoing beacon packets is set to this node ID, - * making beacons appear to originate from that node. - * When unset (0), beacons are sent as the local node. - * A remote admin can only set this field to their own node ID. - */ - uint32 broadcast_send_as_node = 3; + // Tag 3 was broadcast_send_as_node, a node-ID override that rewrote the `from` field of + // outgoing beacon packets so they appeared to originate from another node. Firmware never + // applied it (the assignment was left commented out) and it never reached a tagged release, + // so it is removed rather than kept as a settable no-op. Reserved to prevent reuse. + reserved 3; + reserved "broadcast_send_as_node"; /* * Message to include in each beacon broadcast. Max 100 bytes enforced by firmware. From 4ac5e0fc7e1363daf47aefd718254a584cab4fd6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 28 Aug 2026 10:43:24 -0500 Subject: [PATCH 52/52] Consolidate beacon TX destinations onto broadcast_targets MeshBeaconConfig had two ways to name a beacon destination. broadcast_on_channel / broadcast_on_region / broadcast_on_preset described a single destination with the channel spelled out inline, and broadcast_targets described up to four, each naming its channel by channel-table index. The firmware silently used one or the other depending on whether broadcast_targets was empty. The comments claimed the two were equal and differed only in representation. They were not: an inline ChannelSettings carries name and PSK, so it could transmit on a channel absent from the node's channel table, which channel_index cannot express. That capability is dropped deliberately - there is no use case for beaconing on a channel the node does not have, and provisioning the channel is not a workaround but the intended way to do it. Removes tags 8, 9 and 10 and reserves them. Empty broadcast_targets now means one beacon on the node's running preset and region over the primary channel, which is what the scalar path produced when it was left unset. Also corrects two statements about broadcast_targets that did not match the firmware: copies are sent per distinct destination, not per entry, because entries resolving to the same effective preset/region/channel are deduplicated. MeshBeaconConfig shrinks 324 -> 246 bytes, ModuleConfig 328 -> 250, against a hard 512-byte FromRadio ceiling. Co-Authored-By: Claude Opus 5 --- meshtastic/module_config.options | 2 -- meshtastic/module_config.proto | 47 ++++++++++++-------------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/meshtastic/module_config.options b/meshtastic/module_config.options index ca6e1d603..c825a5b44 100644 --- a/meshtastic/module_config.options +++ b/meshtastic/module_config.options @@ -33,6 +33,4 @@ *MeshBeaconConfig.broadcast_message max_size:101 *MeshBeaconConfig.broadcast_offer_channel.name max_size:12 *MeshBeaconConfig.broadcast_offer_channel.psk max_size:32 -*MeshBeaconConfig.broadcast_on_channel.name max_size:12 -*MeshBeaconConfig.broadcast_on_channel.psk max_size:32 *MeshBeaconConfig.broadcast_targets max_count:4 diff --git a/meshtastic/module_config.proto b/meshtastic/module_config.proto index 65688697c..46b5cbca9 100644 --- a/meshtastic/module_config.proto +++ b/meshtastic/module_config.proto @@ -897,25 +897,14 @@ message ModuleConfig { */ optional Config.LoRaConfig.ModemPreset broadcast_offer_preset = 7; - /* - * Single-target TX channel: channel settings (name + PSK) to send beacons on. - * If unset, beacons go out on the primary channel. Used only when broadcast_targets is empty. - * NOTE: the single-target path embeds the ChannelSettings inline here, whereas a - * broadcast_targets entry references a channel-table slot by channel_index instead — see - * BroadcastTarget. The two paths are equal, first-class options; only this representation differs. - */ - ChannelSettings broadcast_on_channel = 8; - - /* - * Region to use when sending beacons on broadcast_on_preset. - */ - Config.LoRaConfig.RegionCode broadcast_on_region = 9; - - /* - * Modem preset to use when sending beacons. - * If different from current config, the radio is temporarily switched for TX. - */ - optional Config.LoRaConfig.ModemPreset broadcast_on_preset = 10; + // Tags 8, 9 and 10 were broadcast_on_channel / broadcast_on_region / broadcast_on_preset: a + // second way to describe a single beacon destination, used only when broadcast_targets was + // empty. Consolidated onto broadcast_targets so there is one way to name a destination. + // broadcast_on_channel embedded a ChannelSettings inline, which allowed transmitting on a + // channel absent from the node's channel table; that is no longer supported - the channel must + // exist on the node. Never in a tagged release. Reserved to prevent reuse. + reserved 8, 9, 10; + reserved "broadcast_on_channel", "broadcast_on_region", "broadcast_on_preset"; /* * How often to broadcast, in seconds. Min 3600 (1 h), default 3600. @@ -923,8 +912,8 @@ message ModuleConfig { uint32 broadcast_interval_secs = 11; /* - * One entry in the multi-target broadcast list. - * The broadcaster transmits one beacon copy per entry, each on its own radio settings. + * One entry in the broadcast destination list. + * Each entry names one set of radio settings to send a beacon copy on. */ message BroadcastTarget { /* @@ -951,15 +940,13 @@ message ModuleConfig { } /* - * Multi-target broadcast list. - * When non-empty the broadcaster transmits one beacon copy per entry in sequence, - * each temporarily switching the radio to that entry's preset/region/channel. - * When empty, the broadcaster uses the scalar broadcast_on_preset / broadcast_on_region / - * broadcast_on_channel fields instead (the single-target path). - * Single- and multi-target are equal, first-class options — neither is preferred or - * deprecated. They differ only in how the TX channel is named: broadcast_on_channel embeds a - * ChannelSettings inline, while a target references an existing channel-table slot by - * channel_index (see BroadcastTarget). + * Broadcast destination list. + * The broadcaster sends one beacon copy per distinct destination, in sequence, temporarily + * switching the radio to that entry's preset/region/channel for each. + * When empty, a single beacon is sent on the node's running preset and region over the + * primary channel. + * Entries that resolve to the same effective preset, region and channel are deduplicated, so + * a duplicate entry does not produce a second transmission. */ repeated BroadcastTarget broadcast_targets = 13; }