From 9ab49d1431c29e347d26a57060416333b0affa09 Mon Sep 17 00:00:00 2001 From: Dan Ditomaso Date: Tue, 14 Oct 2025 08:54:55 -0400 Subject: [PATCH] Add protobufs repo as git submodule (#882) * feat: add protobufs git submodule * fixes * fixed publishing issue * fixed lockfile --- .github/workflows/release-protobufs.yml | 138 + .gitignore | 2 + .gitmodules | 3 + package.json | 2 +- packages/packages/protobufs | 1 + packages/protobufs/.gitattributes | 3 + .../.github/pull_request_template.md | 30 + packages/protobufs/.github/workflows/ci.yml | 24 + .../.github/workflows/create_tag.yml | 71 + .../protobufs/.github/workflows/publish.yml | 30 + .../.github/workflows/pull_request.yml | 23 + packages/protobufs/.gitignore | 1 + packages/protobufs/.gitmodules | 2 + packages/protobufs/.vscode/extensions.json | 3 + packages/protobufs/.vscode/settings.json | 4 + packages/protobufs/README.md | 16 + packages/protobufs/buf.gen.yaml | 5 + packages/protobufs/buf.yaml | 14 + packages/protobufs/deno.json | 13 + packages/protobufs/meshtastic/admin.options | 19 + packages/protobufs/meshtastic/admin.proto | 582 ++++ packages/protobufs/meshtastic/apponly.options | 1 + packages/protobufs/meshtastic/apponly.proto | 31 + packages/protobufs/meshtastic/atak.options | 8 + packages/protobufs/meshtastic/atak.proto | 263 ++ .../meshtastic/cannedmessages.options | 1 + .../protobufs/meshtastic/cannedmessages.proto | 19 + packages/protobufs/meshtastic/channel.options | 5 + packages/protobufs/meshtastic/channel.proto | 161 ++ .../protobufs/meshtastic/clientonly.options | 4 + .../protobufs/meshtastic/clientonly.proto | 58 + packages/protobufs/meshtastic/config.options | 24 + packages/protobufs/meshtastic/config.proto | 1200 ++++++++ .../meshtastic/connection_status.options | 1 + .../meshtastic/connection_status.proto | 120 + .../protobufs/meshtastic/device_ui.options | 12 + packages/protobufs/meshtastic/device_ui.proto | 389 +++ .../protobufs/meshtastic/deviceonly.options | 18 + .../protobufs/meshtastic/deviceonly.proto | 301 ++ .../protobufs/meshtastic/interdevice.options | 1 + .../protobufs/meshtastic/interdevice.proto | 44 + packages/protobufs/meshtastic/localonly.proto | 140 + packages/protobufs/meshtastic/mesh.options | 92 + packages/protobufs/meshtastic/mesh.proto | 2409 +++++++++++++++++ .../meshtastic/module_config.options | 29 + .../protobufs/meshtastic/module_config.proto | 870 ++++++ packages/protobufs/meshtastic/mqtt.options | 8 + packages/protobufs/meshtastic/mqtt.proto | 112 + packages/protobufs/meshtastic/paxcount.proto | 29 + packages/protobufs/meshtastic/portnums.proto | 244 ++ packages/protobufs/meshtastic/powermon.proto | 103 + .../meshtastic/remote_hardware.proto | 75 + packages/protobufs/meshtastic/rtttl.options | 1 + packages/protobufs/meshtastic/rtttl.proto | 19 + .../protobufs/meshtastic/storeforward.options | 1 + .../protobufs/meshtastic/storeforward.proto | 218 ++ .../protobufs/meshtastic/telemetry.options | 18 + packages/protobufs/meshtastic/telemetry.proto | 808 ++++++ packages/protobufs/meshtastic/xmodem.options | 6 + packages/protobufs/meshtastic/xmodem.proto | 27 + packages/protobufs/nanopb.proto | 185 ++ packages/protobufs/package.json | 30 + packages/protobufs/packages/ts/README.md | 16 + packages/protobufs/packages/ts/deno.json | 13 + packages/protobufs/packages/ts/deno.lock | 384 +++ packages/protobufs/packages/ts/mod.ts | 20 + packages/web/src/routes.tsx | 36 + pnpm-lock.yaml | 796 ++++-- 68 files changed, 10100 insertions(+), 236 deletions(-) create mode 100644 .github/workflows/release-protobufs.yml create mode 100644 .gitmodules create mode 160000 packages/packages/protobufs create mode 100644 packages/protobufs/.gitattributes create mode 100644 packages/protobufs/.github/pull_request_template.md create mode 100644 packages/protobufs/.github/workflows/ci.yml create mode 100644 packages/protobufs/.github/workflows/create_tag.yml create mode 100644 packages/protobufs/.github/workflows/publish.yml create mode 100644 packages/protobufs/.github/workflows/pull_request.yml create mode 100644 packages/protobufs/.gitignore create mode 100644 packages/protobufs/.gitmodules create mode 100644 packages/protobufs/.vscode/extensions.json create mode 100644 packages/protobufs/.vscode/settings.json create mode 100644 packages/protobufs/README.md create mode 100644 packages/protobufs/buf.gen.yaml create mode 100644 packages/protobufs/buf.yaml create mode 100644 packages/protobufs/deno.json create mode 100644 packages/protobufs/meshtastic/admin.options create mode 100644 packages/protobufs/meshtastic/admin.proto create mode 100644 packages/protobufs/meshtastic/apponly.options create mode 100644 packages/protobufs/meshtastic/apponly.proto create mode 100644 packages/protobufs/meshtastic/atak.options create mode 100644 packages/protobufs/meshtastic/atak.proto create mode 100644 packages/protobufs/meshtastic/cannedmessages.options create mode 100644 packages/protobufs/meshtastic/cannedmessages.proto create mode 100644 packages/protobufs/meshtastic/channel.options create mode 100644 packages/protobufs/meshtastic/channel.proto create mode 100644 packages/protobufs/meshtastic/clientonly.options create mode 100644 packages/protobufs/meshtastic/clientonly.proto create mode 100644 packages/protobufs/meshtastic/config.options create mode 100644 packages/protobufs/meshtastic/config.proto create mode 100644 packages/protobufs/meshtastic/connection_status.options create mode 100644 packages/protobufs/meshtastic/connection_status.proto create mode 100644 packages/protobufs/meshtastic/device_ui.options create mode 100644 packages/protobufs/meshtastic/device_ui.proto create mode 100644 packages/protobufs/meshtastic/deviceonly.options create mode 100644 packages/protobufs/meshtastic/deviceonly.proto create mode 100644 packages/protobufs/meshtastic/interdevice.options create mode 100644 packages/protobufs/meshtastic/interdevice.proto create mode 100644 packages/protobufs/meshtastic/localonly.proto create mode 100644 packages/protobufs/meshtastic/mesh.options create mode 100644 packages/protobufs/meshtastic/mesh.proto create mode 100644 packages/protobufs/meshtastic/module_config.options create mode 100644 packages/protobufs/meshtastic/module_config.proto create mode 100644 packages/protobufs/meshtastic/mqtt.options create mode 100644 packages/protobufs/meshtastic/mqtt.proto create mode 100644 packages/protobufs/meshtastic/paxcount.proto create mode 100644 packages/protobufs/meshtastic/portnums.proto create mode 100644 packages/protobufs/meshtastic/powermon.proto create mode 100644 packages/protobufs/meshtastic/remote_hardware.proto create mode 100644 packages/protobufs/meshtastic/rtttl.options create mode 100644 packages/protobufs/meshtastic/rtttl.proto create mode 100644 packages/protobufs/meshtastic/storeforward.options create mode 100644 packages/protobufs/meshtastic/storeforward.proto create mode 100644 packages/protobufs/meshtastic/telemetry.options create mode 100644 packages/protobufs/meshtastic/telemetry.proto create mode 100644 packages/protobufs/meshtastic/xmodem.options create mode 100644 packages/protobufs/meshtastic/xmodem.proto create mode 100644 packages/protobufs/nanopb.proto create mode 100644 packages/protobufs/package.json create mode 100644 packages/protobufs/packages/ts/README.md create mode 100644 packages/protobufs/packages/ts/deno.json create mode 100644 packages/protobufs/packages/ts/deno.lock create mode 100644 packages/protobufs/packages/ts/mod.ts diff --git a/.github/workflows/release-protobufs.yml b/.github/workflows/release-protobufs.yml new file mode 100644 index 00000000..0857e735 --- /dev/null +++ b/.github/workflows/release-protobufs.yml @@ -0,0 +1,138 @@ +name: Create Protobuf Release for JSR + +on: + workflow_dispatch: + inputs: + version: + description: "Version to publish (e.g. v1.2.3). Used when manually dispatching." + required: true + type: string + dry_run: + description: "Don't actually publish to JSR (passes --dry-run)." + required: false + type: boolean + default: false + +permissions: write-all + +jobs: + codegen: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Show files exist + run: | + set -euxo pipefail + ls -la packages/ts || true + cat packages/ts/deno.json + + - name: Determine VERSION + run: | + set -euo pipefail + if [ -n "${{ inputs.version }}" ]; then + VERSION="${{ inputs.version }}" + else + echo "No 'version' input. Provide inputs.version." >&2 + exit 1 + fi + STRIPPED="${VERSION#v}" + echo "VERSION=$STRIPPED" >> "$GITHUB_ENV" + echo "Resolved VERSION=$STRIPPED" + + - name: Set Package Versions to current tag + working-directory: packages/ts + run: | + set -euxo pipefail + for f in deno.json; do + test -f "$f" + jq --arg version "${VERSION//\//-}" ' + walk( + if type == "string" and test("__PACKAGE_VERSION__") + then sub("__PACKAGE_VERSION__"; $version) + else . + end + ) + ' "$f" > "$f.tmp" + mv "$f.tmp" "$f" + done + + - name: Setup Buf + uses: bufbuild/buf-setup-action@main + with: + github_token: ${{ github.token }} + + - name: Generate code + run: pnpm --filter @meshtastic/protobufs build + + + - name: Move generated .ts files and clean up + run: | + set -euxo pipefail + SRC_DIR="packages/protobufs/packages/ts/dist/meshtastic" + DEST_DIR="packages/protobufs/packages/ts/dist" + + if [ -d "$SRC_DIR" ]; then + shopt -s nullglob + ts_files=("$SRC_DIR"/*.ts) + if [ ${#ts_files[@]} -gt 0 ]; then + mv "$SRC_DIR"/*.ts "$DEST_DIR"/ + fi + rm -rf "$SRC_DIR" + else + echo "Source directory not found: $SRC_DIR" >&2 + exit 1 + fi + + # Remove nanopb_pb.ts if present + if [ -f "$DEST_DIR/nanopb_pb.ts" ]; then + rm "$DEST_DIR/nanopb_pb.ts" + fi + + - name: Copy license & README + run: | + cp LICENSE packages/ts + cp README.md packages/ts + + - name: Upload TypeScript code + uses: actions/upload-artifact@v4 + with: + name: ts_code + path: packages/ts + + - name: Push to schema registry + env: + BUF_TOKEN: ${{ secrets.BUF_TOKEN }} + run: buf push --tag ${{ github.ref_name }} + + publish-jsr: + runs-on: ubuntu-24.04 + needs: codegen + permissions: + contents: read + id-token: write + env: + DRY_RUN: ${{ inputs.dry_run }} + steps: + - name: Download TypeScript code + uses: actions/download-artifact@v4 + with: + name: ts_code + + - name: Set up Deno + uses: denoland/setup-deno@main + with: + deno-version: rc + + - name: Publish to JSR + run: | + set -euxo pipefail + FLAGS="--unstable-sloppy-imports" + if [ "${DRY_RUN}" = "true" ]; then + FLAGS="$FLAGS --dry-run" + echo "Running publish in dry-run mode..." + fi + deno publish $FLAGS diff --git a/.gitignore b/.gitignore index 97442988..cb8f36f4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ __screenshots__* npm/ .idea **/LICENSE + +packages/protobufs/packages/ts/dist diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e8694829 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "packages/packages/protobufs"] + path = packages/packages/protobufs + url = https://github.com/meshtastic/protobufs diff --git a/package.json b/package.json index 6ab13905..739e6f08 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test": "vitest" }, "dependencies": { - "@bufbuild/protobuf": "^2.8.0", + "@bufbuild/protobuf": "^2.9.0", "@meshtastic/protobufs": "npm:@jsr/meshtastic__protobufs@^2.7.8", "ste-simple-events": "^3.0.11", "tslog": "^4.9.3" diff --git a/packages/packages/protobufs b/packages/packages/protobufs new file mode 160000 index 00000000..a1b8c3d1 --- /dev/null +++ b/packages/packages/protobufs @@ -0,0 +1 @@ +Subproject commit a1b8c3d171445b2eebfd4b5bd1e4876f3bbed605 diff --git a/packages/protobufs/.gitattributes b/packages/protobufs/.gitattributes new file mode 100644 index 00000000..314766e9 --- /dev/null +++ b/packages/protobufs/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf diff --git a/packages/protobufs/.github/pull_request_template.md b/packages/protobufs/.github/pull_request_template.md new file mode 100644 index 00000000..8db5e305 --- /dev/null +++ b/packages/protobufs/.github/pull_request_template.md @@ -0,0 +1,30 @@ + + +# What does this PR do? + + + +> [Related Issue](https://github.com/meshtastic/protobufs/issues/0) + +## Checklist before merging + +- [ ] All top level messages commented +- [ ] All enum members have unique descriptions + + +### New Hardware Model Acceptance Policy + +Due to limited availability and ongoing support, new Hardware Models will only be accepted from [Meshtastic Backers and Partners](https://meshtastic.com/). The Meshtastic team reserves the right to make exceptions to this policy. + +#### Alternative for Community Contributors + +You are welcome to use one of the existing DIY hardware models in your PlatformIO environment and create a pull request in the firmware project. Please note the following conditions: + +- The device will **not** be officially supported by the core Meshtastic team. +- The device will **not** appear in the [Web Flasher](https://flasher.meshtastic.org/) or Github release assets. +- You will be responsible for ongoing maintenance and support. +- Community-contributed / DIY hardware models are considered experimental and will likely have limited or no testing. + +#### Getting Official Support + +To have your hardware model officially supported and included in the Meshtastic ecosystem, consider becoming a Meshtastic Backer or Partner. Visit [meshtastic.com](https://meshtastic.com/) for more information about partnership opportunities. diff --git a/packages/protobufs/.github/workflows/ci.yml b/packages/protobufs/.github/workflows/ci.yml new file mode 100644 index 00000000..f38ad9f1 --- /dev/null +++ b/packages/protobufs/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: Push commit to schema registry + +permissions: + contents: read + +on: + push: + branches: + - master + +jobs: + push_to_registry: + name: Push to schema registry + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Push to schema registry + uses: bufbuild/buf-action@v1.2.0 + with: + github_token: ${{ github.token }} + token: ${{ secrets.BUF_TOKEN }} + push: true diff --git a/packages/protobufs/.github/workflows/create_tag.yml b/packages/protobufs/.github/workflows/create_tag.yml new file mode 100644 index 00000000..a1e97684 --- /dev/null +++ b/packages/protobufs/.github/workflows/create_tag.yml @@ -0,0 +1,71 @@ +name: Create tag + +permissions: + contents: write + +on: + workflow_dispatch: + inputs: + increment_type: + type: choice + description: Select the type of version increment + required: true + options: + - patch + - minor + - major + +jobs: + increment_version: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: version + name: Get current version + run: | + VERSION=$(git describe --abbrev=0 --tags) + + # Split version into major, minor, and patch + MAJOR=$(echo $VERSION | awk -F '.' '{print $1}' | cut -c 2-) + MINOR=$(echo $VERSION | awk -F '.' '{print $2}') + PATCH=$(echo $VERSION | awk -F '.' '{print $3}') + + # Increment the appropriate part of the version + if [[ ${{ inputs.increment_type }} == "patch" ]]; then + PATCH=$((PATCH + 1)) + elif [[ ${{ inputs.increment_type }} == "minor" ]]; then + MINOR=$((MINOR + 1)) + PATCH=0 + elif [[ ${{ inputs.increment_type }} == "major" ]]; then + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + fi + + # Update the version + echo "NEW_VERSION=v$MAJOR.$MINOR.$PATCH" >> $GITHUB_OUTPUT + + - name: Create release + uses: ncipollo/release-action@v1 + with: + name: Meshtastic Protobufs ${{ steps.version.outputs.NEW_VERSION }} + tag: ${{ steps.version.outputs.NEW_VERSION }} + generateReleaseNotes: true + token: ${{ github.token }} + + - name: Setup Buf + uses: bufbuild/buf-action@v1.2.0 + with: + 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 }} diff --git a/packages/protobufs/.github/workflows/publish.yml b/packages/protobufs/.github/workflows/publish.yml new file mode 100644 index 00000000..70c229ec --- /dev/null +++ b/packages/protobufs/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Push new version to schema registry + +permissions: + contents: read + +on: + push: + tags: + - "**" + +jobs: + push_to_registry: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Buf + uses: bufbuild/buf-action@v1.2.0 + with: + 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 ${{ github.ref_name }} diff --git a/packages/protobufs/.github/workflows/pull_request.yml b/packages/protobufs/.github/workflows/pull_request.yml new file mode 100644 index 00000000..6df3b323 --- /dev/null +++ b/packages/protobufs/.github/workflows/pull_request.yml @@ -0,0 +1,23 @@ +name: pull-request + +permissions: + contents: read + pull-requests: write + +on: pull_request +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Buf PR Checks + uses: bufbuild/buf-action@v1.2.0 + with: + github_token: ${{ github.token }} + token: ${{ secrets.BUF_TOKEN }} + format: true + lint: true + breaking: true diff --git a/packages/protobufs/.gitignore b/packages/protobufs/.gitignore new file mode 100644 index 00000000..e43b0f98 --- /dev/null +++ b/packages/protobufs/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/packages/protobufs/.gitmodules b/packages/protobufs/.gitmodules new file mode 100644 index 00000000..3654e812 --- /dev/null +++ b/packages/protobufs/.gitmodules @@ -0,0 +1,2 @@ +[submodule "packages/protobufs"] + branch = master diff --git a/packages/protobufs/.vscode/extensions.json b/packages/protobufs/.vscode/extensions.json new file mode 100644 index 00000000..157b2919 --- /dev/null +++ b/packages/protobufs/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["pbkit.vscode-pbkit", "bufbuild.vscode-buf"] +} diff --git a/packages/protobufs/.vscode/settings.json b/packages/protobufs/.vscode/settings.json new file mode 100644 index 00000000..60415c3e --- /dev/null +++ b/packages/protobufs/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "pbkit.vscode-pbkit" +} diff --git a/packages/protobufs/README.md b/packages/protobufs/README.md new file mode 100644 index 00000000..9e361977 --- /dev/null +++ b/packages/protobufs/README.md @@ -0,0 +1,16 @@ +# 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) +[![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) + +## Overview + +The [Protobuf](https://developers.google.com/protocol-buffers) message definitions for the Meshtastic project (used by apps and the device firmware). + +**[Documentation/API Reference](https://buf.build/meshtastic/protobufs)** + +## Stats + +![Alt](https://repobeats.axiom.co/api/embed/47e9ee1d81d9c0fdd2b4b5b4c673adb1756f6db5.svg "Repobeats analytics image") diff --git a/packages/protobufs/buf.gen.yaml b/packages/protobufs/buf.gen.yaml new file mode 100644 index 00000000..1effc836 --- /dev/null +++ b/packages/protobufs/buf.gen.yaml @@ -0,0 +1,5 @@ +version: v2 +plugins: + - remote: buf.build/bufbuild/es + out: packages/ts/dist + opt: target=ts diff --git a/packages/protobufs/buf.yaml b/packages/protobufs/buf.yaml new file mode 100644 index 00000000..642e538e --- /dev/null +++ b/packages/protobufs/buf.yaml @@ -0,0 +1,14 @@ +version: v1 +name: buf.build/meshtastic/protobufs +deps: [] +build: + excludes: [] +breaking: + use: + - FILE +lint: + ignore_only: + PACKAGE_DEFINED: + - nanopb.proto + use: + - MINIMAL diff --git a/packages/protobufs/deno.json b/packages/protobufs/deno.json new file mode 100644 index 00000000..b5f91df0 --- /dev/null +++ b/packages/protobufs/deno.json @@ -0,0 +1,13 @@ +{ + "name": "@meshtastic/protobufs", + "version": "__PACKAGE_VERSION__", + "exports": { + ".": "./mod.ts" + }, + "imports": { + "@bufbuild/protobuf": "npm:@bufbuild/protobuf@^2.9.0" + }, + "publish": { + "exclude": ["!dist"] + } +} diff --git a/packages/protobufs/meshtastic/admin.options b/packages/protobufs/meshtastic/admin.options new file mode 100644 index 00000000..4a28ff2d --- /dev/null +++ b/packages/protobufs/meshtastic/admin.options @@ -0,0 +1,19 @@ +*AdminMessage.payload_variant anonymous_oneof:true + +*AdminMessage.session_passkey max_size:8 + +*AdminMessage.InputEvent.event_code int_size:8 +*AdminMessage.InputEvent.kb_char int_size:8 +*AdminMessage.InputEvent.touch_x int_size:16 +*AdminMessage.InputEvent.touch_y int_size:16 + +*AdminMessage.set_canned_message_module_messages max_size:201 +*AdminMessage.get_canned_message_module_messages_response max_size:201 +*AdminMessage.delete_file_request max_size:201 + +*AdminMessage.set_ringtone_message max_size:231 +*AdminMessage.get_ringtone_response max_size:231 + +*HamParameters.call_sign max_size:8 +*HamParameters.short_name max_size:5 +*NodeRemoteHardwarePinsResponse.node_remote_hardware_pins max_count:16 diff --git a/packages/protobufs/meshtastic/admin.proto b/packages/protobufs/meshtastic/admin.proto new file mode 100644 index 00000000..8dc1dc29 --- /dev/null +++ b/packages/protobufs/meshtastic/admin.proto @@ -0,0 +1,582 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; +import "meshtastic/connection_status.proto"; +import "meshtastic/device_ui.proto"; +import "meshtastic/mesh.proto"; +import "meshtastic/module_config.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "AdminProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * This message is handled by the Admin module and is responsible for all settings/channel read/write operations. + * This message is used to do settings operations to both remote AND local nodes. + * (Prior to 1.2 these operations were done via special ToRadio operations) + */ +message AdminMessage { + /* + * The node generates this key and sends it with any get_x_response packets. + * The client MUST include the same key with any set_x commands. Key expires after 300 seconds. + * Prevents replay attacks for admin messages. + */ + bytes session_passkey = 101; + + /* + * TODO: REPLACE + */ + enum ConfigType { + /* + * TODO: REPLACE + */ + DEVICE_CONFIG = 0; + + /* + * TODO: REPLACE + */ + POSITION_CONFIG = 1; + + /* + * TODO: REPLACE + */ + POWER_CONFIG = 2; + + /* + * TODO: REPLACE + */ + NETWORK_CONFIG = 3; + + /* + * TODO: REPLACE + */ + DISPLAY_CONFIG = 4; + + /* + * TODO: REPLACE + */ + LORA_CONFIG = 5; + + /* + * TODO: REPLACE + */ + BLUETOOTH_CONFIG = 6; + + /* + * TODO: REPLACE + */ + SECURITY_CONFIG = 7; + + /* + * Session key config + */ + SESSIONKEY_CONFIG = 8; + + /* + * device-ui config + */ + DEVICEUI_CONFIG = 9; + } + + /* + * TODO: REPLACE + */ + enum ModuleConfigType { + /* + * TODO: REPLACE + */ + MQTT_CONFIG = 0; + + /* + * TODO: REPLACE + */ + SERIAL_CONFIG = 1; + + /* + * TODO: REPLACE + */ + EXTNOTIF_CONFIG = 2; + + /* + * TODO: REPLACE + */ + STOREFORWARD_CONFIG = 3; + + /* + * TODO: REPLACE + */ + RANGETEST_CONFIG = 4; + + /* + * TODO: REPLACE + */ + TELEMETRY_CONFIG = 5; + + /* + * TODO: REPLACE + */ + CANNEDMSG_CONFIG = 6; + + /* + * TODO: REPLACE + */ + AUDIO_CONFIG = 7; + + /* + * TODO: REPLACE + */ + REMOTEHARDWARE_CONFIG = 8; + + /* + * TODO: REPLACE + */ + NEIGHBORINFO_CONFIG = 9; + + /* + * TODO: REPLACE + */ + AMBIENTLIGHTING_CONFIG = 10; + + /* + * TODO: REPLACE + */ + DETECTIONSENSOR_CONFIG = 11; + + /* + * TODO: REPLACE + */ + PAXCOUNTER_CONFIG = 12; + } + + enum BackupLocation { + /* + * Backup to the internal flash + */ + FLASH = 0; + + /* + * Backup to the SD card + */ + SD = 1; + } + + /* + * Input event message to be sent to the node. + */ + message InputEvent { + /* + * The input event code + */ + uint32 event_code = 1; + /* + * Keyboard character code + */ + uint32 kb_char = 2; + /* + * The touch X coordinate + */ + uint32 touch_x = 3; + /* + * The touch Y coordinate + */ + uint32 touch_y = 4; + } + + /* + * TODO: REPLACE + */ + oneof payload_variant { + /* + * Send the specified channel in the response to this message + * NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) + */ + uint32 get_channel_request = 1; + + /* + * TODO: REPLACE + */ + Channel get_channel_response = 2; + + /* + * Send the current owner data in the response to this message. + */ + bool get_owner_request = 3; + + /* + * TODO: REPLACE + */ + User get_owner_response = 4; + + /* + * Ask for the following config data to be sent + */ + ConfigType get_config_request = 5; + + /* + * Send the current Config in the response to this message. + */ + Config get_config_response = 6; + + /* + * Ask for the following config data to be sent + */ + ModuleConfigType get_module_config_request = 7; + + /* + * Send the current Config in the response to this message. + */ + ModuleConfig get_module_config_response = 8; + + /* + * Get the Canned Message Module messages in the response to this message. + */ + bool get_canned_message_module_messages_request = 10; + + /* + * Get the Canned Message Module messages in the response to this message. + */ + string get_canned_message_module_messages_response = 11; + + /* + * Request the node to send device metadata (firmware, protobuf version, etc) + */ + bool get_device_metadata_request = 12; + + /* + * Device metadata response + */ + DeviceMetadata get_device_metadata_response = 13; + + /* + * Get the Ringtone in the response to this message. + */ + bool get_ringtone_request = 14; + + /* + * Get the Ringtone in the response to this message. + */ + string get_ringtone_response = 15; + + /* + * Request the node to send it's connection status + */ + bool get_device_connection_status_request = 16; + + /* + * Device connection status response + */ + DeviceConnectionStatus get_device_connection_status_response = 17; + + /* + * Setup a node for licensed amateur (ham) radio operation + */ + HamParameters set_ham_mode = 18; + + /* + * Get the mesh's nodes with their available gpio pins for RemoteHardware module use + */ + bool get_node_remote_hardware_pins_request = 19; + + /* + * Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use + */ + NodeRemoteHardwarePinsResponse get_node_remote_hardware_pins_response = 20; + + /* + * Enter (UF2) DFU mode + * Only implemented on NRF52 currently + */ + bool enter_dfu_mode_request = 21; + + /* + * Delete the file by the specified path from the device + */ + string delete_file_request = 22; + + /* + * Set zero and offset for scale chips + */ + uint32 set_scale = 23; + + /* + * Backup the node's preferences + */ + BackupLocation backup_preferences = 24; + + /* + * Restore the node's preferences + */ + BackupLocation restore_preferences = 25; + + /* + * Remove backups of the node's preferences + */ + BackupLocation remove_backup_preferences = 26; + + /* + * Send an input event to the node. + * This is used to trigger physical input events like button presses, touch events, etc. + */ + InputEvent send_input_event = 27; + + /* + * Set the owner for this node + */ + User set_owner = 32; + + /* + * Set channels (using the new API). + * A special channel is the "primary channel". + * The other records are secondary channels. + * Note: only one channel can be marked as primary. + * If the client sets a particular channel to be primary, the previous channel will be set to SECONDARY automatically. + */ + Channel set_channel = 33; + + /* + * Set the current Config + */ + Config set_config = 34; + + /* + * Set the current Config + */ + ModuleConfig set_module_config = 35; + + /* + * Set the Canned Message Module messages text. + */ + string set_canned_message_module_messages = 36; + + /* + * Set the ringtone for ExternalNotification. + */ + string set_ringtone_message = 37; + + /* + * Remove the node by the specified node-num from the NodeDB on the device + */ + uint32 remove_by_nodenum = 38; + + /* + * Set specified node-num to be favorited on the NodeDB on the device + */ + uint32 set_favorite_node = 39; + + /* + * Set specified node-num to be un-favorited on the NodeDB on the device + */ + uint32 remove_favorite_node = 40; + + /* + * Set fixed position data on the node and then set the position.fixed_position = true + */ + Position set_fixed_position = 41; + + /* + * Clear fixed position coordinates and then set position.fixed_position = false + */ + bool remove_fixed_position = 42; + + /* + * Set time only on the node + * Convenience method to set the time on the node (as Net quality) without any other position data + */ + fixed32 set_time_only = 43; + + /* + * Tell the node to send the stored ui data. + */ + bool get_ui_config_request = 44; + + /* + * Reply stored device ui data. + */ + DeviceUIConfig get_ui_config_response = 45; + + /* + * Tell the node to store UI data persistently. + */ + DeviceUIConfig store_ui_config = 46; + + /* + * Set specified node-num to be ignored on the NodeDB on the device + */ + uint32 set_ignored_node = 47; + + /* + * Set specified node-num to be un-ignored on the NodeDB on the device + */ + uint32 remove_ignored_node = 48; + + /* + * Begins an edit transaction for config, module config, owner, and channel settings changes + * This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) + */ + bool begin_edit_settings = 64; + + /* + * Commits an open transaction for any edits made to config, module config, owner, and channel settings + */ + bool commit_edit_settings = 65; + + /* + * Add a contact (User) to the nodedb + */ + SharedContact add_contact = 66; + + /* + * Initiate or respond to a key verification request + */ + KeyVerificationAdmin key_verification = 67; + + /* + * Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. + */ + int32 factory_reset_device = 94; + + /* + * Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) + * Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. + */ + int32 reboot_ota_seconds = 95; + + /* + * This message is only supported for the simulator Portduino build. + * If received the simulator will exit successfully. + */ + bool exit_simulator = 96; + + /* + * Tell the node to reboot in this many seconds (or <0 to cancel reboot) + */ + int32 reboot_seconds = 97; + + /* + * Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) + */ + int32 shutdown_seconds = 98; + + /* + * Tell the node to factory reset config; all device state and configuration will be returned to factory defaults; BLE bonds will be preserved. + */ + int32 factory_reset_config = 99; + + /* + * Tell the node to reset the nodedb. + */ + int32 nodedb_reset = 100; + } +} + +/* + * Parameters for setting up Meshtastic for ameteur radio usage + */ +message HamParameters { + /* + * Amateur radio call sign, eg. KD2ABC + */ + string call_sign = 1; + + /* + * Transmit power in dBm at the LoRA transceiver, not including any amplification + */ + int32 tx_power = 2; + + /* + * The selected frequency of LoRA operation + * Please respect your local laws, regulations, and band plans. + * Ensure your radio is capable of operating of the selected frequency before setting this. + */ + float frequency = 3; + + /* + * Optional short name of user + */ + string short_name = 4; +} + +/* + * Response envelope for node_remote_hardware_pins + */ +message NodeRemoteHardwarePinsResponse { + /* + * Nodes and their respective remote hardware GPIO pins + */ + repeated NodeRemoteHardwarePin node_remote_hardware_pins = 1; +} + +message SharedContact { + /* + * The node number of the contact + */ + uint32 node_num = 1; + + /* + * The User of the contact + */ + User user = 2; + + /* + * Add this contact to the blocked / ignored list + */ + bool should_ignore = 3; + + /* + * Set the IS_KEY_MANUALLY_VERIFIED bit + */ + bool manually_verified = 4; +} + +/* + * This message is used by a client to initiate or complete a key verification + */ +message KeyVerificationAdmin { + /* + * Three stages of this request. + */ + enum MessageType { + /* + * This is the first stage, where a client initiates + */ + INITIATE_VERIFICATION = 0; + + /* + * After the nonce has been returned over the mesh, the client prompts for the security number + * And uses this message to provide it to the node. + */ + PROVIDE_SECURITY_NUMBER = 1; + + /* + * Once the user has compared the verification message, this message notifies the node. + */ + DO_VERIFY = 2; + + /* + * This is the cancel path, can be taken at any point + */ + DO_NOT_VERIFY = 3; + } + + MessageType message_type = 1; + + /* + * The nodenum we're requesting + */ + uint32 remote_nodenum = 2; + + /* + * The nonce is used to track the connection + */ + uint64 nonce = 3; + + /* + * The 4 digit code generated by the remote node, and communicated outside the mesh + */ + optional uint32 security_number = 4; +} diff --git a/packages/protobufs/meshtastic/apponly.options b/packages/protobufs/meshtastic/apponly.options new file mode 100644 index 00000000..28244de0 --- /dev/null +++ b/packages/protobufs/meshtastic/apponly.options @@ -0,0 +1 @@ +*ChannelSet.settings max_count:8 diff --git a/packages/protobufs/meshtastic/apponly.proto b/packages/protobufs/meshtastic/apponly.proto new file mode 100644 index 00000000..100833f4 --- /dev/null +++ b/packages/protobufs/meshtastic/apponly.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "AppOnlyProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * This is the most compact possible representation for a set of channels. + * It includes only one PRIMARY channel (which must be first) and + * any SECONDARY channels. + * No DISABLED channels are included. + * This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL + */ +message ChannelSet { + /* + * Channel list with settings + */ + repeated ChannelSettings settings = 1; + + /* + * LoRa config + */ + Config.LoRaConfig lora_config = 2; +} diff --git a/packages/protobufs/meshtastic/atak.options b/packages/protobufs/meshtastic/atak.options new file mode 100644 index 00000000..cec1ca32 --- /dev/null +++ b/packages/protobufs/meshtastic/atak.options @@ -0,0 +1,8 @@ +*Contact.callsign max_size:120 +*Contact.device_callsign max_size:120 +*Status.battery int_size:8 +*PLI.course int_size:16 +*GeoChat.message max_size:200 +*GeoChat.to max_size:120 +*GeoChat.to_callsign max_size:120 +*TAKPacket.detail max_size:220 \ No newline at end of file diff --git a/packages/protobufs/meshtastic/atak.proto b/packages/protobufs/meshtastic/atak.proto new file mode 100644 index 00000000..5dc08c9a --- /dev/null +++ b/packages/protobufs/meshtastic/atak.proto @@ -0,0 +1,263 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ATAKProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Packets for the official ATAK Plugin + */ +message TAKPacket { + /* + * Are the payloads strings compressed for LoRA transport? + */ + bool is_compressed = 1; + /* + * The contact / callsign for ATAK user + */ + Contact contact = 2; + /* + * The group for ATAK user + */ + Group group = 3; + /* + * The status of the ATAK EUD + */ + Status status = 4; + /* + * The payload of the packet + */ + oneof payload_variant { + /* + * TAK position report + */ + PLI pli = 5; + /* + * ATAK GeoChat message + */ + GeoChat chat = 6; + + /* + * Generic CoT detail XML + * May be compressed / truncated by the sender (EUD) + */ + bytes detail = 7; + } +} + +/* + * ATAK GeoChat message + */ +message GeoChat { + /* + * The text message + */ + string message = 1; + + /* + * Uid recipient of the message + */ + optional string to = 2; + + /* + * Callsign of the recipient for the message + */ + optional string to_callsign = 3; +} + +/* + * ATAK Group + * <__group role='Team Member' name='Cyan'/> + */ +message Group { + /* + * Role of the group member + */ + MemberRole role = 1; + /* + * Team (color) + * Default Cyan + */ + Team team = 2; +} + +enum Team { + /* + * Unspecifed + */ + Unspecifed_Color = 0; + /* + * White + */ + White = 1; + /* + * Yellow + */ + Yellow = 2; + /* + * Orange + */ + Orange = 3; + /* + * Magenta + */ + Magenta = 4; + /* + * Red + */ + Red = 5; + /* + * Maroon + */ + Maroon = 6; + /* + * Purple + */ + Purple = 7; + /* + * Dark Blue + */ + Dark_Blue = 8; + /* + * Blue + */ + Blue = 9; + /* + * Cyan + */ + Cyan = 10; + /* + * Teal + */ + Teal = 11; + /* + * Green + */ + Green = 12; + /* + * Dark Green + */ + Dark_Green = 13; + /* + * Brown + */ + Brown = 14; +} + +/* + * Role of the group member + */ +enum MemberRole { + /* + * Unspecifed + */ + Unspecifed = 0; + /* + * Team Member + */ + TeamMember = 1; + /* + * Team Lead + */ + TeamLead = 2; + /* + * Headquarters + */ + HQ = 3; + /* + * Airsoft enthusiast + */ + Sniper = 4; + /* + * Medic + */ + Medic = 5; + /* + * ForwardObserver + */ + ForwardObserver = 6; + /* + * Radio Telephone Operator + */ + RTO = 7; + /* + * Doggo + */ + K9 = 8; +} + +/* + * ATAK EUD Status + * + */ +message Status { + /* + * Battery level + */ + uint32 battery = 1; +} + +/* + * ATAK Contact + * + */ +message Contact { + /* + * Callsign + */ + string callsign = 1; + + /* + * Device callsign + */ + string device_callsign = 2; + /* + * IP address of endpoint in integer form (0.0.0.0 default) + */ + // fixed32 enpoint_address = 3; + /* + * Port of endpoint (4242 default) + */ + // uint32 endpoint_port = 4; + /* + * Phone represented as integer + * Terrible practice, but we really need the wire savings + */ + // uint32 phone = 4; +} + +/* + * Position Location Information from ATAK + */ +message PLI { + /* + * The new preferred location encoding, multiply by 1e-7 to get degrees + * in floating point + */ + sfixed32 latitude_i = 1; + + /* + * The new preferred location encoding, multiply by 1e-7 to get degrees + * in floating point + */ + sfixed32 longitude_i = 2; + + /* + * Altitude (ATAK prefers HAE) + */ + int32 altitude = 3; + + /* + * Speed + */ + uint32 speed = 4; + + /* + * Course in degrees + */ + uint32 course = 5; +} diff --git a/packages/protobufs/meshtastic/cannedmessages.options b/packages/protobufs/meshtastic/cannedmessages.options new file mode 100644 index 00000000..c1d537bb --- /dev/null +++ b/packages/protobufs/meshtastic/cannedmessages.options @@ -0,0 +1 @@ +*CannedMessageModuleConfig.messages max_size:201 diff --git a/packages/protobufs/meshtastic/cannedmessages.proto b/packages/protobufs/meshtastic/cannedmessages.proto new file mode 100644 index 00000000..baa51343 --- /dev/null +++ b/packages/protobufs/meshtastic/cannedmessages.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "CannedMessageConfigProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Canned message module configuration. + */ +message CannedMessageModuleConfig { + /* + * Predefined messages for canned message module separated by '|' characters. + */ + string messages = 1; +} diff --git a/packages/protobufs/meshtastic/channel.options b/packages/protobufs/meshtastic/channel.options new file mode 100644 index 00000000..d0bdcbc9 --- /dev/null +++ b/packages/protobufs/meshtastic/channel.options @@ -0,0 +1,5 @@ +*Channel.index int_size:8 + +# 256 bit or 128 bit psk key +*ChannelSettings.psk max_size:32 +*ChannelSettings.name max_size:12 diff --git a/packages/protobufs/meshtastic/channel.proto b/packages/protobufs/meshtastic/channel.proto new file mode 100644 index 00000000..4b772421 --- /dev/null +++ b/packages/protobufs/meshtastic/channel.proto @@ -0,0 +1,161 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ChannelProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * This information can be encoded as a QRcode/url so that other users can configure + * their radio to join the same channel. + * A note about how channel names are shown to users: channelname-X + * poundsymbol is a prefix used to indicate this is a channel name (idea from @professr). + * Where X is a letter from A-Z (base 26) representing a hash of the PSK for this + * channel - so that if the user changes anything about the channel (which does + * force a new PSK) this letter will also change. Thus preventing user confusion if + * two friends try to type in a channel name of "BobsChan" and then can't talk + * because their PSKs will be different. + * The PSK is hashed into this letter by "0x41 + [xor all bytes of the psk ] modulo 26" + * This also allows the option of someday if people have the PSK off (zero), the + * users COULD type in a channel name and be able to talk. + * FIXME: Add description of multi-channel support and how primary vs secondary channels are used. + * FIXME: explain how apps use channels for security. + * explain how remote settings and remote gpio are managed as an example + */ +message ChannelSettings { + /* + * Deprecated in favor of LoraConfig.channel_num + */ + uint32 channel_num = 1 [deprecated = true]; + + /* + * A simple pre-shared key for now for crypto. + * Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256). + * A special shorthand is used for 1 byte long psks. + * These psks should be treated as only minimally secure, + * because they are listed in this source code. + * Those bytes are mapped using the following scheme: + * `0` = No crypto + * `1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01} + * `2` through 10 = The default channel key, except with 1 through 9 added to the last byte. + * Shown to user as simple1 through 10 + */ + bytes psk = 2; + + /* + * A SHORT name that will be packed into the URL. + * Less than 12 bytes. + * Something for end users to call the channel + * If this is the empty string it is assumed that this channel + * is the special (minimally secure) "Default"channel. + * In user interfaces it should be rendered as a local language translation of "X". + * For channel_num hashing empty string will be treated as "X". + * Where "X" is selected based on the English words listed above for ModemPreset + */ + string name = 3; + + /* + * Used to construct a globally unique channel ID. + * The full globally unique ID will be: "name.id" where ID is shown as base36. + * Assuming that the number of meshtastic users is below 20K (true for a long time) + * the chance of this 64 bit random number colliding with anyone else is super low. + * And the penalty for collision is low as well, it just means that anyone trying to decrypt channel messages might need to + * try multiple candidate channels. + * Any time a non wire compatible change is made to a channel, this field should be regenerated. + * There are a small number of 'special' globally known (and fairly) insecure standard channels. + * Those channels do not have a numeric id included in the settings, but instead it is pulled from + * a table of well known IDs. + * (see Well Known Channels FIXME) + */ + fixed32 id = 4; + + /* + * If true, messages on the mesh will be sent to the *public* internet by any gateway ndoe + */ + bool uplink_enabled = 5; + + /* + * If true, messages seen on the internet will be forwarded to the local mesh. + */ + bool downlink_enabled = 6; + + /* + * Per-channel module settings. + */ + ModuleSettings module_settings = 7; + + /* + * Whether or not we should receive notifactions / alerts through this channel + */ + bool mute = 8; +} + +/* + * This message is specifically for modules to store per-channel configuration data. + */ +message ModuleSettings { + /* + * Bits of precision for the location sent in position packets. + */ + uint32 position_precision = 1; + + /* + * Controls whether or not the phone / clients should mute the current channel + * Useful for noisy public channels you don't necessarily want to disable + */ + bool is_client_muted = 2; +} + +/* + * A pair of a channel number, mode and the (sharable) settings for that channel + */ +message Channel { + /* + * How this channel is being used (or not). + * Note: this field is an enum to give us options for the future. + * In particular, someday we might make a 'SCANNING' option. + * SCANNING channels could have different frequencies and the radio would + * occasionally check that freq to see if anything is being transmitted. + * For devices that have multiple physical radios attached, we could keep multiple PRIMARY/SCANNING channels active at once to allow + * cross band routing as needed. + * If a device has only a single radio (the common case) only one channel can be PRIMARY at a time + * (but any number of SECONDARY channels can't be sent received on that common frequency) + */ + enum Role { + /* + * This channel is not in use right now + */ + DISABLED = 0; + + /* + * This channel is used to set the frequency for the radio - all other enabled channels must be SECONDARY + */ + PRIMARY = 1; + + /* + * Secondary channels are only used for encryption/decryption/authentication purposes. + * Their radio settings (freq etc) are ignored, only psk is used. + */ + SECONDARY = 2; + } + + /* + * The index of this channel in the channel table (from 0 to MAX_NUM_CHANNELS-1) + * (Someday - not currently implemented) An index of -1 could be used to mean "set by name", + * in which case the target node will find and set the channel by settings.name. + */ + int32 index = 1; + + /* + * The new settings, or NULL to disable that channel + */ + ChannelSettings settings = 2; + + /* + * TODO: REPLACE + */ + Role role = 3; +} diff --git a/packages/protobufs/meshtastic/clientonly.options b/packages/protobufs/meshtastic/clientonly.options new file mode 100644 index 00000000..c47944a0 --- /dev/null +++ b/packages/protobufs/meshtastic/clientonly.options @@ -0,0 +1,4 @@ +*DeviceProfile.long_name max_size:40 +*DeviceProfile.short_name max_size:5 +*DeviceProfile.ringtone max_size:231 +*DeviceProfile.canned_messages max_size:201 \ No newline at end of file diff --git a/packages/protobufs/meshtastic/clientonly.proto b/packages/protobufs/meshtastic/clientonly.proto new file mode 100644 index 00000000..2b919ef7 --- /dev/null +++ b/packages/protobufs/meshtastic/clientonly.proto @@ -0,0 +1,58 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/localonly.proto"; +import "meshtastic/mesh.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ClientOnlyProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * This abstraction is used to contain any configuration for provisioning a node on any client. + * It is useful for importing and exporting configurations. + */ +message DeviceProfile { + /* + * Long name for the node + */ + optional string long_name = 1; + + /* + * Short name of the node + */ + optional string short_name = 2; + + /* + * The url of the channels from our node + */ + optional string channel_url = 3; + + /* + * The Config of the node + */ + optional LocalConfig config = 4; + + /* + * The ModuleConfig of the node + */ + optional LocalModuleConfig module_config = 5; + + /* + * Fixed position data + */ + optional Position fixed_position = 6; + + /* + * Ringtone for ExternalNotification + */ + optional string ringtone = 7; + + /* + * Predefined messages for CannedMessage + */ + optional string canned_messages = 8; +} diff --git a/packages/protobufs/meshtastic/config.options b/packages/protobufs/meshtastic/config.options new file mode 100644 index 00000000..3f6d81c9 --- /dev/null +++ b/packages/protobufs/meshtastic/config.options @@ -0,0 +1,24 @@ +# longest current is 45 chars, plan with a bit of buffer +*DeviceConfig.tzdef max_size:65 +*DeviceConfig.buzzer_mode int_size:8 + + +*NetworkConfig.wifi_ssid max_size:33 +*NetworkConfig.wifi_psk max_size:65 +*NetworkConfig.ntp_server max_size:33 +*NetworkConfig.rsyslog_server max_size:33 + +# Max of three ignored nodes for our testing +*LoRaConfig.ignore_incoming max_count:3 + +*LoRaConfig.tx_power int_size:8 +*LoRaConfig.bandwidth int_size:16 +*LoRaConfig.coding_rate int_size:8 +*LoRaConfig.channel_num int_size:16 + +*PowerConfig.device_battery_ina_address int_size:8 + +*SecurityConfig.public_key max_size:32 +*SecurityConfig.private_key max_size:32 +*SecurityConfig.admin_key max_size:32 +*SecurityConfig.admin_key max_count:3 diff --git a/packages/protobufs/meshtastic/config.proto b/packages/protobufs/meshtastic/config.proto new file mode 100644 index 00000000..f17a0785 --- /dev/null +++ b/packages/protobufs/meshtastic/config.proto @@ -0,0 +1,1200 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/device_ui.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ConfigProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +message Config { + /* + * Configuration + */ + message DeviceConfig { + /* + * Defines the device's role on the Mesh network + */ + enum Role { + /* + * Description: App connected or stand alone messaging device. + * Technical Details: Default Role + */ + CLIENT = 0; + /* + * Description: Device that does not forward packets from other devices. + */ + CLIENT_MUTE = 1; + + /* + * Description: Infrastructure node for extending network coverage by relaying messages. Visible in Nodes list. + * Technical Details: Mesh packets will prefer to be routed over this node. This node will not be used by client apps. + * The wifi radio and the oled screen will be put to sleep. + * This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. + */ + ROUTER = 2; + + /* + * Description: Combination of both ROUTER and CLIENT. Not for mobile devices. + * Deprecated in v2.3.15 because improper usage is impacting public meshes: Use ROUTER or CLIENT instead. + */ + + ROUTER_CLIENT = 3 [deprecated = true]; + + /* + * Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list. + * Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry + * or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. + * Deprecated in v2.7.11 because it creates "holes" in the mesh rebroadcast chain. + */ + REPEATER = 4 [deprecated = true]; + + /* + * Description: Broadcasts GPS position packets as priority. + * Technical Details: Position Mesh packets will be prioritized higher and sent more frequently by default. + * When used in conjunction with power.is_power_saving = true, nodes will wake up, + * send position, and then sleep for position.position_broadcast_secs seconds. + */ + TRACKER = 5; + + /* + * Description: Broadcasts telemetry packets as priority. + * Technical Details: Telemetry Mesh packets will be prioritized higher and sent more frequently by default. + * When used in conjunction with power.is_power_saving = true, nodes will wake up, + * send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. + */ + SENSOR = 6; + + /* + * Description: Optimized for ATAK system communication and reduces routine broadcasts. + * Technical Details: Used for nodes dedicated for connection to an ATAK EUD. + * Turns off many of the routine broadcasts to favor CoT packet stream + * from the Meshtastic ATAK plugin -> IMeshService -> Node + */ + TAK = 7; + + /* + * Description: Device that only broadcasts as needed for stealth or power savings. + * Technical Details: Used for nodes that "only speak when spoken to" + * Turns all of the routine broadcasts but allows for ad-hoc communication + * Still rebroadcasts, but with local only rebroadcast mode (known meshes only) + * Can be used for clandestine operation or to dramatically reduce airtime / power consumption + */ + CLIENT_HIDDEN = 8; + + /* + * Description: Broadcasts location as message to default channel regularly for to assist with device recovery. + * Technical Details: Used to automatically send a text message to the mesh + * with the current position of the device on a frequent interval: + * "I'm lost! Position: lat / long" + */ + LOST_AND_FOUND = 9; + + /* + * Description: Enables automatic TAK PLI broadcasts and reduces routine broadcasts. + * Technical Details: Turns off many of the routine broadcasts to favor ATAK CoT packet stream + * and automatic TAK PLI (position location information) broadcasts. + * Uses position module configuration to determine TAK PLI broadcast interval. + */ + TAK_TRACKER = 10; + + /* + * Description: Will always rebroadcast packets, but will do so after all other modes. + * Technical Details: Used for router nodes that are intended to provide additional coverage + * in areas not already covered by other routers, or to bridge around problematic terrain, + * but should not be given priority over other routers in order to avoid unnecessaraily + * consuming hops. + */ + ROUTER_LATE = 11; + + /* + * Description: Treats packets from or to favorited nodes as ROUTER, and all other packets as CLIENT. + * Technical Details: Used for stronger attic/roof nodes to distribute messages more widely + * from weaker, indoor, or less-well-positioned nodes. Recommended for users with multiple nodes + * where one CLIENT_BASE acts as a more powerful base station, such as an attic/roof node. + */ + CLIENT_BASE = 12; + } + + /* + * Defines the device's behavior for how messages are rebroadcast + */ + enum RebroadcastMode { + /* + * Default behavior. + * Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params. + */ + ALL = 0; + + /* + * Same as behavior as ALL but skips packet decoding and simply rebroadcasts them. + * Only available in Repeater role. Setting this on any other roles will result in ALL behavior. + */ + ALL_SKIP_DECODING = 1; + + /* + * Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. + * Only rebroadcasts message on the nodes local primary / secondary channels. + */ + LOCAL_ONLY = 2; + + /* + * Ignores observed messages from foreign meshes like LOCAL_ONLY, + * but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB) + */ + KNOWN_ONLY = 3; + + /* + * Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role. + */ + NONE = 4; + + /* + * Ignores packets from non-standard portnums such as: TAK, RangeTest, PaxCounter, etc. + * Only rebroadcasts packets with standard portnums: NodeInfo, Text, Position, Telemetry, and Routing. + */ + CORE_PORTNUMS_ONLY = 5; + } + + /* + * Defines buzzer behavior for audio feedback + */ + enum BuzzerMode { + /* + * Default behavior. + * Buzzer is enabled for all audio feedback including button presses and alerts. + */ + ALL_ENABLED = 0; + + /* + * Disabled. + * All buzzer audio feedback is disabled. + */ + DISABLED = 1; + + /* + * Notifications Only. + * Buzzer is enabled only for notifications and alerts, but not for button presses. + * External notification config determines the specifics of the notification behavior. + */ + NOTIFICATIONS_ONLY = 2; + + /* + * Non-notification system buzzer tones only. + * Buzzer is enabled only for non-notification tones such as button presses, startup, shutdown, but not for alerts. + */ + SYSTEM_ONLY = 3; + + /* + * Direct Message notifications only. + * Buzzer is enabled only for direct messages and alerts, but not for button presses. + * External notification config determines the specifics of the notification behavior. + */ + DIRECT_MSG_ONLY = 4; + } + + /* + * Sets the role of node + */ + Role role = 1; + + /* + * Disabling this will disable the SerialConsole by not initilizing the StreamAPI + * Moved to SecurityConfig + */ + bool serial_enabled = 2 [deprecated = true]; + + /* + * For boards without a hard wired button, this is the pin number that will be used + * Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. + */ + uint32 button_gpio = 4; + + /* + * For boards without a PWM buzzer, this is the pin number that will be used + * Defaults to PIN_BUZZER if defined. + */ + uint32 buzzer_gpio = 5; + + /* + * Sets the role of node + */ + RebroadcastMode rebroadcast_mode = 6; + + /* + * Send our nodeinfo this often + * Defaults to 900 Seconds (15 minutes) + */ + uint32 node_info_broadcast_secs = 7; + + /* + * Treat double tap interrupt on supported accelerometers as a button press if set to true + */ + bool double_tap_as_button_press = 8; + + /* + * If true, device is considered to be "managed" by a mesh administrator + * Clients should then limit available configuration and administrative options inside the user interface + * Moved to SecurityConfig + */ + bool is_managed = 9 [deprecated = true]; + + /* + * Disables the triple-press of user button to enable or disable GPS + */ + bool disable_triple_click = 10; + + /* + * POSIX Timezone definition string from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv. + */ + string tzdef = 11; + + /* + * If true, disable the default blinking LED (LED_PIN) behavior on the device + */ + bool led_heartbeat_disabled = 12; + + /* + * Controls buzzer behavior for audio feedback + * Defaults to ENABLED + */ + BuzzerMode buzzer_mode = 13; + } + + /* + * Position Config + */ + message PositionConfig { + /* + * Bit field of boolean configuration options, indicating which optional + * fields to include when assembling POSITION messages. + * Longitude, latitude, altitude, speed, heading, and DOP + * are always included (also time if GPS-synced) + * NOTE: the more fields are included, the larger the message will be - + * leading to longer airtime and a higher risk of packet loss + */ + enum PositionFlags { + /* + * Required for compilation + */ + UNSET = 0x0000; + + /* + * Include an altitude value (if available) + */ + ALTITUDE = 0x0001; + + /* + * Altitude value is MSL + */ + ALTITUDE_MSL = 0x0002; + + /* + * Include geoidal separation + */ + GEOIDAL_SEPARATION = 0x0004; + + /* + * Include the DOP value ; PDOP used by default, see below + */ + DOP = 0x0008; + + /* + * If POS_DOP set, send separate HDOP / VDOP values instead of PDOP + */ + HVDOP = 0x0010; + + /* + * Include number of "satellites in view" + */ + SATINVIEW = 0x0020; + + /* + * Include a sequence number incremented per packet + */ + SEQ_NO = 0x0040; + + /* + * Include positional timestamp (from GPS solution) + */ + TIMESTAMP = 0x0080; + + /* + * Include positional heading + * Intended for use with vehicle not walking speeds + * walking speeds are likely to be error prone like the compass + */ + HEADING = 0x0100; + + /* + * Include positional speed + * Intended for use with vehicle not walking speeds + * walking speeds are likely to be error prone like the compass + */ + SPEED = 0x0200; + } + + enum GpsMode { + /* + * GPS is present but disabled + */ + DISABLED = 0; + + /* + * GPS is present and enabled + */ + ENABLED = 1; + + /* + * GPS is not present on the device + */ + NOT_PRESENT = 2; + } + + /* + * We should send our position this often (but only if it has changed significantly) + * Defaults to 15 minutes + */ + uint32 position_broadcast_secs = 1; + + /* + * Adaptive position braoadcast, which is now the default. + */ + bool position_broadcast_smart_enabled = 2; + + /* + * If set, this node is at a fixed position. + * We will generate GPS position updates at the regular interval, but use whatever the last lat/lon/alt we have for the node. + * The lat/lon/alt can be set by an internal GPS or with the help of the app. + */ + bool fixed_position = 3; + + /* + * Is GPS enabled for this node? + */ + bool gps_enabled = 4 [deprecated = true]; + + /* + * How often should we try to get GPS position (in seconds) + * or zero for the default of once every 30 seconds + * or a very large value (maxint) to update only once at boot. + */ + uint32 gps_update_interval = 5; + + /* + * Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time + */ + uint32 gps_attempt_time = 6 [deprecated = true]; + + /* + * Bit field of boolean configuration options for POSITION messages + * (bitwise OR of PositionFlags) + */ + uint32 position_flags = 7; + + /* + * (Re)define GPS_RX_PIN for your board. + */ + uint32 rx_gpio = 8; + + /* + * (Re)define GPS_TX_PIN for your board. + */ + uint32 tx_gpio = 9; + + /* + * The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled + */ + uint32 broadcast_smart_minimum_distance = 10; + + /* + * The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled + */ + uint32 broadcast_smart_minimum_interval_secs = 11; + + /* + * (Re)define PIN_GPS_EN for your board. + */ + uint32 gps_en_gpio = 12; + + /* + * Set where GPS is enabled, disabled, or not present + */ + GpsMode gps_mode = 13; + } + + /* + * Power Config\ + * See [Power Config](/docs/settings/config/power) for additional power config details. + */ + message PowerConfig { + /* + * Description: Will sleep everything as much as possible, for the tracker and sensor role this will also include the lora radio. + * Don't use this setting if you want to use your device with the phone apps or are using a device without a user button. + * Technical Details: Works for ESP32 devices and NRF52 devices in the Sensor or Tracker roles + */ + bool is_power_saving = 1; + + /* + * Description: If non-zero, the device will fully power off this many seconds after external power is removed. + */ + uint32 on_battery_shutdown_after_secs = 2; + + /* + * Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k) + * Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation. + * https://meshtastic.org/docs/configuration/radio/power/#adc-multiplier-override + * Should be set to floating point value between 2 and 6 + */ + float adc_multiplier_override = 3; + + /* + * Description: The number of seconds for to wait before turning off BLE in No Bluetooth states + * Technical Details: ESP32 Only 0 for default of 1 minute + */ + uint32 wait_bluetooth_secs = 4; + + /* + * Super Deep Sleep Seconds + * While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep + * for this value (default 1 year) or a button press + * 0 for default of one year + */ + uint32 sds_secs = 6; + + /* + * Description: In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on + * Technical Details: ESP32 Only 0 for default of 300 + */ + uint32 ls_secs = 7; + + /* + * Description: While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value + * Technical Details: ESP32 Only 0 for default of 10 seconds + */ + uint32 min_wake_secs = 8; + + /* + * I2C address of INA_2XX to use for reading device battery voltage + */ + uint32 device_battery_ina_address = 9; + + /* + * If non-zero, we want powermon log outputs. With the particular (bitfield) sources enabled. + * Note: we picked an ID of 32 so that lower more efficient IDs can be used for more frequently used options. + */ + uint64 powermon_enables = 32; + } + + /* + * Network Config + */ + message NetworkConfig { + enum AddressMode { + /* + * obtain ip address via DHCP + */ + DHCP = 0; + + /* + * use static ip address + */ + STATIC = 1; + } + + message IpV4Config { + /* + * Static IP address + */ + fixed32 ip = 1; + + /* + * Static gateway address + */ + fixed32 gateway = 2; + + /* + * Static subnet mask + */ + fixed32 subnet = 3; + + /* + * Static DNS server address + */ + fixed32 dns = 4; + } + + /* + * Enable WiFi (disables Bluetooth) + */ + bool wifi_enabled = 1; + + /* + * If set, this node will try to join the specified wifi network and + * acquire an address via DHCP + */ + string wifi_ssid = 3; + + /* + * If set, will be use to authenticate to the named wifi + */ + string wifi_psk = 4; + + /* + * NTP server to use if WiFi is conneced, defaults to `meshtastic.pool.ntp.org` + */ + string ntp_server = 5; + + /* + * Enable Ethernet + */ + bool eth_enabled = 6; + + /* + * acquire an address via DHCP or assign static + */ + AddressMode address_mode = 7; + + /* + * struct to keep static address + */ + IpV4Config ipv4_config = 8; + + /* + * rsyslog Server and Port + */ + string rsyslog_server = 9; + + /* + * Flags for enabling/disabling network protocols + */ + uint32 enabled_protocols = 10; + + /* + * Enable/Disable ipv6 support + */ + bool ipv6_enabled = 11; + + /* + * Available flags auxiliary network protocols + */ + enum ProtocolFlags { + /* + * Do not broadcast packets over any network protocol + */ + NO_BROADCAST = 0x0000; + + /* + * Enable broadcasting packets via UDP over the local network + */ + UDP_BROADCAST = 0x0001; + } + } + + /* + * Display Config + */ + message DisplayConfig { + /* + * Deprecated in 2.7.4: Unused + */ + enum DeprecatedGpsCoordinateFormat { + UNUSED = 0; + } + + /* + * Unit display preference + */ + enum DisplayUnits { + /* + * Metric (Default) + */ + METRIC = 0; + + /* + * Imperial + */ + IMPERIAL = 1; + } + + /* + * Override OLED outo detect with this if it fails. + */ + enum OledType { + /* + * Default / Autodetect + */ + OLED_AUTO = 0; + + /* + * Default / Autodetect + */ + OLED_SSD1306 = 1; + + /* + * Default / Autodetect + */ + OLED_SH1106 = 2; + + /* + * Can not be auto detected but set by proto. Used for 128x64 screens + */ + OLED_SH1107 = 3; + + /* + * Can not be auto detected but set by proto. Used for 128x128 screens + */ + OLED_SH1107_128_128 = 4; + } + + /* + * Number of seconds the screen stays on after pressing the user button or receiving a message + * 0 for default of one minute MAXUINT for always on + */ + uint32 screen_on_secs = 1; + + /* + * Deprecated in 2.7.4: Unused + * How the GPS coordinates are formatted on the OLED screen. + */ + DeprecatedGpsCoordinateFormat gps_format = 2 [deprecated = true]; + + /* + * Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. + * Potentially useful for devices without user buttons. + */ + uint32 auto_screen_carousel_secs = 3; + + /* + * If this is set, the displayed compass will always point north. if unset, the old behaviour + * (top of display is heading direction) is used. + */ + bool compass_north_top = 4 [deprecated = true]; + + /* + * Flip screen vertically, for cases that mount the screen upside down + */ + bool flip_screen = 5; + + /* + * Perferred display units + */ + DisplayUnits units = 6; + + /* + * Override auto-detect in screen + */ + OledType oled = 7; + + enum DisplayMode { + /* + * Default. The old style for the 128x64 OLED screen + */ + DEFAULT = 0; + + /* + * Rearrange display elements to cater for bicolor OLED displays + */ + TWOCOLOR = 1; + + /* + * Same as TwoColor, but with inverted top bar. Not so good for Epaper displays + */ + INVERTED = 2; + + /* + * TFT Full Color Displays (not implemented yet) + */ + COLOR = 3; + } + /* + * Display Mode + */ + DisplayMode displaymode = 8; + + /* + * Print first line in pseudo-bold? FALSE is original style, TRUE is bold + */ + bool heading_bold = 9; + + /* + * Should we wake the screen up on accelerometer detected motion or tap + */ + bool wake_on_tap_or_motion = 10; + + enum CompassOrientation { + /* + * The compass and the display are in the same orientation. + */ + DEGREES_0 = 0; + + /* + * Rotate the compass by 90 degrees. + */ + DEGREES_90 = 1; + + /* + * Rotate the compass by 180 degrees. + */ + DEGREES_180 = 2; + + /* + * Rotate the compass by 270 degrees. + */ + DEGREES_270 = 3; + + /* + * Don't rotate the compass, but invert the result. + */ + DEGREES_0_INVERTED = 4; + + /* + * Rotate the compass by 90 degrees and invert. + */ + DEGREES_90_INVERTED = 5; + + /* + * Rotate the compass by 180 degrees and invert. + */ + DEGREES_180_INVERTED = 6; + + /* + * Rotate the compass by 270 degrees and invert. + */ + DEGREES_270_INVERTED = 7; + } + + /* + * Indicates how to rotate or invert the compass output to accurate display on the display. + */ + CompassOrientation compass_orientation = 11; + + /* + * If false (default), the device will display the time in 24-hour format on screen. + * If true, the device will display the time in 12-hour format on screen. + */ + bool use_12h_clock = 12; + + /* + * If false (default), the device will use short names for various display screens. + * If true, node names will show in long format + */ + bool use_long_node_name = 13; + } + + /* + * Lora Config + */ + message LoRaConfig { + enum RegionCode { + /* + * Region is not set + */ + UNSET = 0; + + /* + * United States + */ + US = 1; + + /* + * European Union 433mhz + */ + EU_433 = 2; + + /* + * European Union 868mhz + */ + EU_868 = 3; + + /* + * China + */ + CN = 4; + + /* + * Japan + */ + JP = 5; + + /* + * Australia / New Zealand + */ + ANZ = 6; + + /* + * Korea + */ + KR = 7; + + /* + * Taiwan + */ + TW = 8; + + /* + * Russia + */ + RU = 9; + + /* + * India + */ + IN = 10; + + /* + * New Zealand 865mhz + */ + NZ_865 = 11; + + /* + * Thailand + */ + TH = 12; + + /* + * WLAN Band + */ + LORA_24 = 13; + + /* + * Ukraine 433mhz + */ + UA_433 = 14; + + /* + * Ukraine 868mhz + */ + UA_868 = 15; + + /* + * Malaysia 433mhz + */ + MY_433 = 16; + + /* + * Malaysia 919mhz + */ + MY_919 = 17; + + /* + * Singapore 923mhz + */ + SG_923 = 18; + + /* + * Philippines 433mhz + */ + PH_433 = 19; + + /* + * Philippines 868mhz + */ + PH_868 = 20; + + /* + * Philippines 915mhz + */ + PH_915 = 21; + + /* + * Australia / New Zealand 433MHz + */ + ANZ_433 = 22; + + /* + * Kazakhstan 433MHz + */ + KZ_433 = 23; + + /* + * Kazakhstan 863MHz + */ + KZ_863 = 24; + + /* + * Nepal 865MHz + */ + NP_865 = 25; + + /* + * Brazil 902MHz + */ + BR_902 = 26; + } + + /* + * Standard predefined channel settings + * Note: these mappings must match ModemPreset Choice in the device code. + */ + enum ModemPreset { + /* + * Long Range - Fast + */ + LONG_FAST = 0; + + /* + * Long Range - Slow + */ + LONG_SLOW = 1; + + /* + * Very Long Range - Slow + * Deprecated in 2.5: Works only with txco and is unusably slow + */ + VERY_LONG_SLOW = 2 [deprecated = true]; + + /* + * Medium Range - Slow + */ + MEDIUM_SLOW = 3; + + /* + * Medium Range - Fast + */ + MEDIUM_FAST = 4; + + /* + * Short Range - Slow + */ + SHORT_SLOW = 5; + + /* + * Short Range - Fast + */ + SHORT_FAST = 6; + + /* + * Long Range - Moderately Fast + */ + LONG_MODERATE = 7; + + /* + * Short Range - Turbo + * This is the fastest preset and the only one with 500kHz bandwidth. + * It is not legal to use in all regions due to this wider bandwidth. + */ + SHORT_TURBO = 8; + } + + /* + * When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate` + * will be taked from their respective manually defined fields + */ + bool use_preset = 1; + + /* + * Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH. + * As a heuristic: If bandwidth is specified, do not use modem_config. + * Because protobufs take ZERO space when the value is zero this works out nicely. + * This value is replaced by bandwidth/spread_factor/coding_rate. + * If you'd like to experiment with other options add them to MeshRadio.cpp in the device code. + */ + ModemPreset modem_preset = 2; + + /* + * Bandwidth in MHz + * Certain bandwidth numbers are 'special' and will be converted to the + * appropriate floating point value: 31 -> 31.25MHz + */ + uint32 bandwidth = 3; + + /* + * A number from 7 to 12. + * Indicates number of chirps per symbol as 1< 7 results in the default + */ + uint32 hop_limit = 8; + + /* + * Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests. + * Defaults to false + */ + bool tx_enabled = 9; + + /* + * If zero, then use default max legal continuous power (ie. something that won't + * burn out the radio hardware) + * In most cases you should use zero here. + * Units are in dBm. + */ + int32 tx_power = 10; + + /* + * This controls the actual hardware frequency the radio transmits on. + * Most users should never need to be exposed to this field/concept. + * A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region). + * If ZERO then the rule is "use the old channel name hash based + * algorithm to derive the channel number") + * If using the hash algorithm the channel number will be: hash(channel_name) % + * NUM_CHANNELS (Where num channels depends on the regulatory region). + */ + uint32 channel_num = 11; + + /* + * If true, duty cycle limits will be exceeded and thus you're possibly not following + * the local regulations if you're not a HAM. + * Has no effect if the duty cycle of the used region is 100%. + */ + bool override_duty_cycle = 12; + + /* + * If true, sets RX boosted gain mode on SX126X based radios + */ + bool sx126x_rx_boosted_gain = 13; + + /* + * This parameter is for advanced users and licensed HAM radio operators. + * Ignore Channel Calculation and use this frequency instead. The frequency_offset + * will still be applied. This will allow you to use out-of-band frequencies. + * Please respect your local laws and regulations. If you are a HAM, make sure you + * enable HAM mode and turn off encryption. + */ + float override_frequency = 14; + + /* + * If true, disable the build-in PA FAN using pin define in RF95_FAN_EN. + */ + bool pa_fan_disabled = 15; + + /* + * For testing it is useful sometimes to force a node to never listen to + * particular other nodes (simulating radio out of range). All nodenums listed + * in ignore_incoming will have packets they send dropped on receive (by router.cpp) + */ + repeated uint32 ignore_incoming = 103; + + /* + * If true, the device will not process any packets received via LoRa that passed via MQTT anywhere on the path towards it. + */ + bool ignore_mqtt = 104; + + /* + * Sets the ok_to_mqtt bit on outgoing packets + */ + bool config_ok_to_mqtt = 105; + } + + message BluetoothConfig { + enum PairingMode { + /* + * Device generates a random PIN that will be shown on the screen of the device for pairing + */ + RANDOM_PIN = 0; + + /* + * Device requires a specified fixed PIN for pairing + */ + FIXED_PIN = 1; + + /* + * Device requires no PIN for pairing + */ + NO_PIN = 2; + } + + /* + * Enable Bluetooth on the device + */ + bool enabled = 1; + + /* + * Determines the pairing strategy for the device + */ + PairingMode mode = 2; + + /* + * Specified PIN for PairingMode.FixedPin + */ + uint32 fixed_pin = 3; + } + + message SecurityConfig { + /* + * 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. + */ + bytes public_key = 1; + + /* + * The private key of the device. + * Used to create a shared key with a remote device. + */ + bytes private_key = 2; + + /* + * The public key authorized to send admin messages to this node. + */ + repeated bytes admin_key = 3; + + /* + * If true, device is considered to be "managed" by a mesh administrator via admin messages + * Device is managed by a mesh administrator. + */ + bool is_managed = 4; + + /* + * Serial Console over the Stream API." + */ + bool serial_enabled = 5; + + /* + * By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). + * Output live debug logging over serial or bluetooth is set to true. + */ + bool debug_log_api_enabled = 6; + + /* + * Allow incoming device control over the insecure legacy admin channel. + */ + bool admin_channel_enabled = 8; + } + + /* + * Blank config request, strictly for getting the session key + */ + message SessionkeyConfig {} + + /* + * Payload Variant + */ + oneof payload_variant { + DeviceConfig device = 1; + PositionConfig position = 2; + PowerConfig power = 3; + NetworkConfig network = 4; + DisplayConfig display = 5; + LoRaConfig lora = 6; + BluetoothConfig bluetooth = 7; + SecurityConfig security = 8; + SessionkeyConfig sessionkey = 9; + DeviceUIConfig device_ui = 10; + } +} diff --git a/packages/protobufs/meshtastic/connection_status.options b/packages/protobufs/meshtastic/connection_status.options new file mode 100644 index 00000000..d4901ddc --- /dev/null +++ b/packages/protobufs/meshtastic/connection_status.options @@ -0,0 +1 @@ +*WifiConnectionStatus.ssid max_size:33 diff --git a/packages/protobufs/meshtastic/connection_status.proto b/packages/protobufs/meshtastic/connection_status.proto new file mode 100644 index 00000000..75515965 --- /dev/null +++ b/packages/protobufs/meshtastic/connection_status.proto @@ -0,0 +1,120 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ConnStatusProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +message DeviceConnectionStatus { + /* + * WiFi Status + */ + optional WifiConnectionStatus wifi = 1; + /* + * WiFi Status + */ + optional EthernetConnectionStatus ethernet = 2; + + /* + * Bluetooth Status + */ + optional BluetoothConnectionStatus bluetooth = 3; + + /* + * Serial Status + */ + optional SerialConnectionStatus serial = 4; +} + +/* + * WiFi connection status + */ +message WifiConnectionStatus { + /* + * Connection status + */ + NetworkConnectionStatus status = 1; + + /* + * WiFi access point SSID + */ + string ssid = 2; + + /* + * RSSI of wireless connection + */ + int32 rssi = 3; +} + +/* + * Ethernet connection status + */ +message EthernetConnectionStatus { + /* + * Connection status + */ + NetworkConnectionStatus status = 1; +} + +/* + * Ethernet or WiFi connection status + */ +message NetworkConnectionStatus { + /* + * IP address of device + */ + fixed32 ip_address = 1; + + /* + * Whether the device has an active connection or not + */ + bool is_connected = 2; + + /* + * Whether the device has an active connection to an MQTT broker or not + */ + bool is_mqtt_connected = 3; + + /* + * Whether the device is actively remote syslogging or not + */ + bool is_syslog_connected = 4; +} + +/* + * Bluetooth connection status + */ +message BluetoothConnectionStatus { + /* + * The pairing PIN for bluetooth + */ + uint32 pin = 1; + + /* + * RSSI of bluetooth connection + */ + int32 rssi = 2; + + /* + * Whether the device has an active connection or not + */ + bool is_connected = 3; +} + +/* + * Serial connection status + */ +message SerialConnectionStatus { + /* + * Serial baud rate + */ + uint32 baud = 1; + + /* + * Whether the device has an active connection or not + */ + bool is_connected = 2; +} diff --git a/packages/protobufs/meshtastic/device_ui.options b/packages/protobufs/meshtastic/device_ui.options new file mode 100644 index 00000000..a8fab466 --- /dev/null +++ b/packages/protobufs/meshtastic/device_ui.options @@ -0,0 +1,12 @@ +*DeviceUIConfig.screen_brightness int_size:8 +*DeviceUIConfig.screen_timeout int_size:16 +*DeviceUIConfig.ring_tone_id int_size:8 +*DeviceUIConfig.calibration_data max_size:16 +*DeviceUIConfig.compass_mode int_size:8 +*DeviceUIConfig.gps_format int_size:8 +*NodeFilter.node_name max_size:16 +*NodeFilter.hops_away int_size:8 +*NodeFilter.channel int_size:8 +*NodeHighlight.node_name max_size:16 +*GeoPoint.zoom int_size:8 +*Map.style max_size:20 diff --git a/packages/protobufs/meshtastic/device_ui.proto b/packages/protobufs/meshtastic/device_ui.proto new file mode 100644 index 00000000..5b6bb5dd --- /dev/null +++ b/packages/protobufs/meshtastic/device_ui.proto @@ -0,0 +1,389 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "DeviceUIProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Protobuf structures for device-ui persistency + */ + +message DeviceUIConfig { + /* + * A version integer used to invalidate saved files when we make incompatible changes. + */ + uint32 version = 1; + + /* + * TFT display brightness 1..255 + */ + uint32 screen_brightness = 2; + + /* + * Screen timeout 0..900 + */ + uint32 screen_timeout = 3; + + /* + * Screen/Settings lock enabled + */ + bool screen_lock = 4; + bool settings_lock = 5; + uint32 pin_code = 6; + + /* + * Color theme + */ + Theme theme = 7; + + /* + * Audible message, banner and ring tone + */ + bool alert_enabled = 8; + bool banner_enabled = 9; + uint32 ring_tone_id = 10; + + /* + * Localization + */ + Language language = 11; + + /* + * Node list filter + */ + NodeFilter node_filter = 12; + + /* + * Node list highlightening + */ + NodeHighlight node_highlight = 13; + + /* + * 8 integers for screen calibration data + */ + bytes calibration_data = 14; + + /* + * Map related data + */ + Map map_data = 15; + + /* + * Compass mode + */ + CompassMode compass_mode = 16; + + /* + * RGB color for BaseUI + * 0xRRGGBB format, e.g. 0xFF0000 for red + */ + uint32 screen_rgb_color = 17; + + /* + * Clockface analog style + * true for analog clockface, false for digital clockface + */ + bool is_clockface_analog = 18; + + /* + * How the GPS coordinates are formatted on the OLED screen. + */ + GpsCoordinateFormat gps_format = 19; + + /* + * How the GPS coordinates are displayed on the OLED screen. + */ + enum GpsCoordinateFormat { + /* + * GPS coordinates are displayed in the normal decimal degrees format: + * DD.DDDDDD DDD.DDDDDD + */ + DEC = 0; + + /* + * GPS coordinates are displayed in the degrees minutes seconds format: + * DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant + */ + DMS = 1; + + /* + * Universal Transverse Mercator format: + * ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing + */ + UTM = 2; + + /* + * Military Grid Reference System format: + * ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, + * E is easting, N is northing + */ + MGRS = 3; + + /* + * Open Location Code (aka Plus Codes). + */ + OLC = 4; + + /* + * Ordnance Survey Grid Reference (the National Grid System of the UK). + * Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, + * E is the easting, N is the northing + */ + OSGR = 5; + + /* + * Maidenhead Locator System + * Described here: https://en.wikipedia.org/wiki/Maidenhead_Locator_System + */ + MLS = 6; + } +} + +message NodeFilter { + /* + * Filter unknown nodes + */ + bool unknown_switch = 1; + + /* + * Filter offline nodes + */ + bool offline_switch = 2; + + /* + * Filter nodes w/o public key + */ + bool public_key_switch = 3; + + /* + * Filter based on hops away + */ + int32 hops_away = 4; + + /* + * Filter nodes w/o position + */ + bool position_switch = 5; + + /* + * Filter nodes by matching name string + */ + string node_name = 6; + + /* + * Filter based on channel + */ + int32 channel = 7; +} + +message NodeHighlight { + /* + * Hightlight nodes w/ active chat + */ + bool chat_switch = 1; + + /* + * Highlight nodes w/ position + */ + bool position_switch = 2; + + /* + * Highlight nodes w/ telemetry data + */ + bool telemetry_switch = 3; + + /* + * Highlight nodes w/ iaq data + */ + bool iaq_switch = 4; + + /* + * Highlight nodes by matching name string + */ + string node_name = 5; +} + +message GeoPoint { + /* + * Zoom level + */ + int32 zoom = 1; + + /* + * Coordinate: latitude + */ + int32 latitude = 2; + + /* + * Coordinate: longitude + */ + int32 longitude = 3; +} + +message Map { + /* + * Home coordinates + */ + GeoPoint home = 1; + + /* + * Map tile style + */ + string style = 2; + + /* + * Map scroll follows GPS + */ + bool follow_gps = 3; +} + +enum CompassMode { + /* + * Compass with dynamic ring and heading + */ + DYNAMIC = 0; + + /* + * Compass with fixed ring and heading + */ + FIXED_RING = 1; + + /* + * Compass with heading and freeze option + */ + FREEZE_HEADING = 2; +} + +enum Theme { + /* + * Dark + */ + DARK = 0; + /* + * Light + */ + LIGHT = 1; + /* + * Red + */ + RED = 2; +} + +/* + * Localization + */ +enum Language { + /* + * English + */ + ENGLISH = 0; + + /* + * French + */ + FRENCH = 1; + + /* + * German + */ + GERMAN = 2; + + /* + * Italian + */ + ITALIAN = 3; + + /* + * Portuguese + */ + PORTUGUESE = 4; + + /* + * Spanish + */ + SPANISH = 5; + + /* + * Swedish + */ + SWEDISH = 6; + + /* + * Finnish + */ + FINNISH = 7; + + /* + * Polish + */ + POLISH = 8; + + /* + * Turkish + */ + TURKISH = 9; + + /* + * Serbian + */ + SERBIAN = 10; + + /* + * Russian + */ + RUSSIAN = 11; + + /* + * Dutch + */ + DUTCH = 12; + + /* + * Greek + */ + GREEK = 13; + + /* + * Norwegian + */ + NORWEGIAN = 14; + + /* + * Slovenian + */ + SLOVENIAN = 15; + + /* + * Ukrainian + */ + UKRAINIAN = 16; + + /* + * Bulgarian + */ + BULGARIAN = 17; + + /* + * Czech + */ + CZECH = 18; + + /* + * Danish + */ + DANISH = 19; + + /* + * Simplified Chinese (experimental) + */ + SIMPLIFIED_CHINESE = 30; + + /* + * Traditional Chinese (experimental) + */ + TRADITIONAL_CHINESE = 31; +} diff --git a/packages/protobufs/meshtastic/deviceonly.options b/packages/protobufs/meshtastic/deviceonly.options new file mode 100644 index 00000000..d6aae0c4 --- /dev/null +++ b/packages/protobufs/meshtastic/deviceonly.options @@ -0,0 +1,18 @@ +# options for nanopb +# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options + +# FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in RAM +*DeviceState.receive_queue max_count:1 + +*ChannelFile.channels max_count:8 + +*DeviceState.node_remote_hardware_pins max_count:12 + +*NodeInfoLite.channel int_size:8 +*NodeInfoLite.hops_away int_size:8 +*NodeInfoLite.next_hop int_size:8 + +*UserLite.long_name max_size:40 +*UserLite.short_name max_size:5 +*UserLite.public_key max_size:32 # public key +*UserLite.macaddr max_size:6 fixed_length:true \ No newline at end of file diff --git a/packages/protobufs/meshtastic/deviceonly.proto b/packages/protobufs/meshtastic/deviceonly.proto new file mode 100644 index 00000000..d449373d --- /dev/null +++ b/packages/protobufs/meshtastic/deviceonly.proto @@ -0,0 +1,301 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; +import "meshtastic/localonly.proto"; +import "meshtastic/mesh.proto"; +import "meshtastic/telemetry.proto"; +import "nanopb.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "DeviceOnly"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; +option (nanopb_fileopt).include = ""; + +/* + * Position with static location information only for NodeDBLite + */ +message PositionLite { + /* + * The new preferred location encoding, multiply by 1e-7 to get degrees + * in floating point + */ + sfixed32 latitude_i = 1; + + /* + * TODO: REPLACE + */ + sfixed32 longitude_i = 2; + + /* + * In meters above MSL (but see issue #359) + */ + int32 altitude = 3; + + /* + * This is usually not sent over the mesh (to save space), but it is sent + * from the phone so that the local device can set its RTC If it is sent over + * the mesh (because there are devices on the mesh without GPS), it will only + * be sent by devices which has a hardware GPS clock. + * seconds since 1970 + */ + fixed32 time = 4; + + /* + * TODO: REPLACE + */ + Position.LocSource location_source = 5; +} + +message UserLite { + /* + * This is the addr of the radio. + */ + bytes macaddr = 1 [deprecated = true]; + + /* + * A full name for this user, i.e. "Kevin Hester" + */ + string long_name = 2; + + /* + * A VERY short name, ideally two characters. + * Suitable for a tiny OLED screen + */ + string short_name = 3; + + /* + * TBEAM, HELTEC, etc... + * Starting in 1.2.11 moved to hw_model enum in the NodeInfo object. + * Apps will still need the string here for older builds + * (so OTA update can find the right image), but if the enum is available it will be used instead. + */ + HardwareModel hw_model = 4; + + /* + * In some regions Ham radio operators have different bandwidth limitations than others. + * If this user is a licensed operator, set this flag. + * Also, "long_name" should be their licence number. + */ + bool is_licensed = 5; + + /* + * Indicates that the user's role in the mesh + */ + Config.DeviceConfig.Role role = 6; + + /* + * The public key of the user's device. + * This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + */ + bytes public_key = 7; + + /* + * Whether or not the node can be messaged + */ + optional bool is_unmessagable = 9; +} + +message NodeInfoLite { + /* + * The node number + */ + uint32 num = 1; + + /* + * The user info for this node + */ + UserLite user = 2; + + /* + * This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true. + * Position.time now indicates the last time we received a POSITION from that node. + */ + PositionLite position = 3; + + /* + * Returns the Signal-to-noise ratio (SNR) of the last received message, + * as measured by the receiver. Return SNR of the last received message in dB + */ + float snr = 4; + + /* + * Set to indicate the last time we received a packet from this node + */ + fixed32 last_heard = 5; + /* + * The latest device metrics for the node. + */ + DeviceMetrics device_metrics = 6; + + /* + * local channel index we heard that node on. Only populated if its not the default channel. + */ + uint32 channel = 7; + + /* + * True if we witnessed the node over MQTT instead of LoRA transport + */ + bool via_mqtt = 8; + + /* + * Number of hops away from us this node is (0 if direct neighbor) + */ + optional uint32 hops_away = 9; + + /* + * True if node is in our favorites list + * Persists between NodeDB internal clean ups + */ + bool is_favorite = 10; + + /* + * True if node is in our ignored list + * Persists between NodeDB internal clean ups + */ + bool is_ignored = 11; + + /* + * Last byte of the node number of the node that should be used as the next hop to reach this node. + */ + uint32 next_hop = 12; + + /* + * Bitfield for storing booleans. + * LSB 0 is_key_manually_verified + */ + uint32 bitfield = 13; +} + +/* + * This message is never sent over the wire, but it is used for serializing DB + * state to flash in the device code + * FIXME, since we write this each time we enter deep sleep (and have infinite + * flash) it would be better to use some sort of append only data structure for + * the receive queue and use the preferences store for the other stuff + */ +message DeviceState { + /* + * Read only settings/info about this node + */ + MyNodeInfo my_node = 2; + + /* + * My owner info + */ + User owner = 3; + + /* + * Received packets saved for delivery to the phone + */ + repeated MeshPacket receive_queue = 5; + + /* + * A version integer used to invalidate old save files when we make + * incompatible changes This integer is set at build time and is private to + * NodeDB.cpp in the device code. + */ + uint32 version = 8; + + /* + * We keep the last received text message (only) stored in the device flash, + * so we can show it on the screen. + * Might be null + */ + MeshPacket rx_text_message = 7; + + /* + * Used only during development. + * Indicates developer is testing and changes should never be saved to flash. + * Deprecated in 2.3.1 + */ + bool no_save = 9 [deprecated = true]; + + /* + * Previously used to manage GPS factory resets. + * Deprecated in 2.5.23 + */ + bool did_gps_reset = 11 [deprecated = true]; + + /* + * We keep the last received waypoint stored in the device flash, + * so we can show it on the screen. + * Might be null + */ + MeshPacket rx_waypoint = 12; + + /* + * The mesh's nodes with their available gpio pins for RemoteHardware module + */ + repeated NodeRemoteHardwarePin node_remote_hardware_pins = 13; +} + +message NodeDatabase { + /* + * A version integer used to invalidate old save files when we make + * incompatible changes This integer is set at build time and is private to + * NodeDB.cpp in the device code. + */ + uint32 version = 1; + + /* + * New lite version of NodeDB to decrease memory footprint + */ + repeated NodeInfoLite nodes = 2 [(nanopb).callback_datatype = "std::vector"]; +} + +/* + * The on-disk saved channels + */ +message ChannelFile { + /* + * The channels our node knows about + */ + repeated Channel channels = 1; + + /* + * A version integer used to invalidate old save files when we make + * incompatible changes This integer is set at build time and is private to + * NodeDB.cpp in the device code. + */ + uint32 version = 2; +} + +/* + * The on-disk backup of the node's preferences + */ +message BackupPreferences { + /* + * The version of the backup + */ + uint32 version = 1; + + /* + * The timestamp of the backup (if node has time) + */ + fixed32 timestamp = 2; + + /* + * The node's configuration + */ + LocalConfig config = 3; + + /* + * The node's module configuration + */ + LocalModuleConfig module_config = 4; + + /* + * The node's channels + */ + ChannelFile channels = 5; + + /* + * The node's user (owner) information + */ + User owner = 6; +} diff --git a/packages/protobufs/meshtastic/interdevice.options b/packages/protobufs/meshtastic/interdevice.options new file mode 100644 index 00000000..97df282f --- /dev/null +++ b/packages/protobufs/meshtastic/interdevice.options @@ -0,0 +1 @@ +*InterdeviceMessage.nmea max_size:1024 diff --git a/packages/protobufs/meshtastic/interdevice.proto b/packages/protobufs/meshtastic/interdevice.proto new file mode 100644 index 00000000..4616c087 --- /dev/null +++ b/packages/protobufs/meshtastic/interdevice.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "InterdeviceProtos"; +option java_package = "com.geeksville.mesh"; +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; + } +} + +message InterdeviceMessage { + // The message data + oneof data { + string nmea = 1; + SensorData sensor = 2; + } +} diff --git a/packages/protobufs/meshtastic/localonly.proto b/packages/protobufs/meshtastic/localonly.proto new file mode 100644 index 00000000..bcb27964 --- /dev/null +++ b/packages/protobufs/meshtastic/localonly.proto @@ -0,0 +1,140 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/config.proto"; +import "meshtastic/module_config.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "LocalOnlyProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Protobuf structures common to apponly.proto and deviceonly.proto + * This is never sent over the wire, only for local use + */ + +message LocalConfig { + /* + * The part of the config that is specific to the Device + */ + Config.DeviceConfig device = 1; + + /* + * The part of the config that is specific to the GPS Position + */ + Config.PositionConfig position = 2; + + /* + * The part of the config that is specific to the Power settings + */ + Config.PowerConfig power = 3; + + /* + * The part of the config that is specific to the Wifi Settings + */ + Config.NetworkConfig network = 4; + + /* + * The part of the config that is specific to the Display + */ + Config.DisplayConfig display = 5; + + /* + * The part of the config that is specific to the Lora Radio + */ + Config.LoRaConfig lora = 6; + + /* + * The part of the config that is specific to the Bluetooth settings + */ + Config.BluetoothConfig bluetooth = 7; + + /* + * A version integer used to invalidate old save files when we make + * incompatible changes This integer is set at build time and is private to + * NodeDB.cpp in the device code. + */ + uint32 version = 8; + + /* + * The part of the config that is specific to Security settings + */ + Config.SecurityConfig security = 9; +} + +message LocalModuleConfig { + /* + * The part of the config that is specific to the MQTT module + */ + ModuleConfig.MQTTConfig mqtt = 1; + + /* + * The part of the config that is specific to the Serial module + */ + ModuleConfig.SerialConfig serial = 2; + + /* + * The part of the config that is specific to the ExternalNotification module + */ + ModuleConfig.ExternalNotificationConfig external_notification = 3; + + /* + * The part of the config that is specific to the Store & Forward module + */ + ModuleConfig.StoreForwardConfig store_forward = 4; + + /* + * The part of the config that is specific to the RangeTest module + */ + ModuleConfig.RangeTestConfig range_test = 5; + + /* + * The part of the config that is specific to the Telemetry module + */ + ModuleConfig.TelemetryConfig telemetry = 6; + + /* + * The part of the config that is specific to the Canned Message module + */ + ModuleConfig.CannedMessageConfig canned_message = 7; + + /* + * The part of the config that is specific to the Audio module + */ + ModuleConfig.AudioConfig audio = 9; + + /* + * The part of the config that is specific to the Remote Hardware module + */ + ModuleConfig.RemoteHardwareConfig remote_hardware = 10; + + /* + * The part of the config that is specific to the Neighbor Info module + */ + ModuleConfig.NeighborInfoConfig neighbor_info = 11; + + /* + * The part of the config that is specific to the Ambient Lighting module + */ + ModuleConfig.AmbientLightingConfig ambient_lighting = 12; + + /* + * The part of the config that is specific to the Detection Sensor module + */ + ModuleConfig.DetectionSensorConfig detection_sensor = 13; + + /* + * Paxcounter Config + */ + ModuleConfig.PaxcounterConfig paxcounter = 14; + + /* + * A version integer used to invalidate old save files when we make + * incompatible changes This integer is set at build time and is private to + * NodeDB.cpp in the device code. + */ + uint32 version = 8; +} diff --git a/packages/protobufs/meshtastic/mesh.options b/packages/protobufs/meshtastic/mesh.options new file mode 100644 index 00000000..37c93416 --- /dev/null +++ b/packages/protobufs/meshtastic/mesh.options @@ -0,0 +1,92 @@ +# options for nanopb +# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options + +*macaddr max_size:6 fixed_length:true # macaddrs +*id max_size:16 # node id strings +*public_key max_size:32 # public key + +*User.long_name max_size:40 +*User.short_name max_size:5 + +*RouteDiscovery.route max_count:8 +*RouteDiscovery.snr_towards max_count:8 +*RouteDiscovery.snr_towards int_size:8 +*RouteDiscovery.route_back max_count:8 +*RouteDiscovery.snr_back max_count:8 +*RouteDiscovery.snr_back int_size:8 + +# note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is +# outside of this envelope +*Data.payload max_size:233 +*Data.bitfield int_size:8 + +*NodeInfo.channel int_size:8 +*NodeInfo.hops_away int_size:8 + +# Big enough for 1.2.28.568032c-d +*MyNodeInfo.firmware_version max_size:18 +*MyNodeInfo.device_id max_size:16 +*MyNodeInfo.pio_env max_size:40 + +*MyNodeInfo.air_period_tx max_count:8 +*MyNodeInfo.air_period_rx max_count:8 + +*MyNodeInfo.firmware_edition int_size:8 +*MyNodeInfo.nodedb_count int_size:16 + +# Note: the actual limit (because of header bytes) on the size of encrypted payloads is 251 bytes, but I use 256 +# here because we might need to fill with zeros for padding to encryption block size (16 bytes per block) +*MeshPacket.encrypted max_size:256 +*MeshPacket.payload_variant anonymous_oneof:true +*MeshPacket.hop_limit int_size:8 +*MeshPacket.hop_start int_size:8 +*MeshPacket.channel int_size:8 +*MeshPacket.next_hop int_size:8 +*MeshPacket.relay_node int_size:8 + +*QueueStatus.res int_size:8 +*QueueStatus.free int_size:8 +*QueueStatus.maxlen int_size:8 + +*ToRadio.payload_variant anonymous_oneof:true + +*FromRadio.payload_variant anonymous_oneof:true + +*Routing.variant anonymous_oneof:true + +*LogRecord.message max_size:384 +*LogRecord.source max_size:32 + +*FileInfo.file_name max_size:228 + +*ClientNotification.message max_size:400 + +*KeyVerificationNumberInform.remote_longname max_size:40 +*KeyVerificationNumberRequest.remote_longname max_size:40 +*KeyVerificationFinal.remote_longname max_size:40 +*KeyVerificationFinal.verification_characters max_size:10 + +*KeyVerification.hash1 max_size:32 +*KeyVerification.hash2 max_size:32 + + +# MyMessage.name max_size:40 +# or fixed_length or fixed_count, or max_count + +#This value may want to be a few bytes smaller to compensate for the parent fields. +*Compressed.data max_size:233 + +*Waypoint.name max_size:30 +*Waypoint.description max_size:100 + +*NeighborInfo.neighbors max_count:10 + +*DeviceMetadata.firmware_version max_size:18 + +*MqttClientProxyMessage.topic max_size:60 +*MqttClientProxyMessage.data max_size:435 +*MqttClientProxyMessage.text max_size:435 + +*ChunkedPayload.chunk_count int_size:16 +*ChunkedPayload.chunk_index int_size:16 +*ChunkedPayload.payload_chunk max_size:228 \ No newline at end of file diff --git a/packages/protobufs/meshtastic/mesh.proto b/packages/protobufs/meshtastic/mesh.proto new file mode 100644 index 00000000..59f8c101 --- /dev/null +++ b/packages/protobufs/meshtastic/mesh.proto @@ -0,0 +1,2409 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/channel.proto"; +import "meshtastic/config.proto"; +import "meshtastic/device_ui.proto"; +import "meshtastic/module_config.proto"; +import "meshtastic/portnums.proto"; +import "meshtastic/telemetry.proto"; +import "meshtastic/xmodem.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "MeshProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * A GPS Position + */ +message Position { + /* + * The new preferred location encoding, multiply by 1e-7 to get degrees + * in floating point + */ + optional sfixed32 latitude_i = 1; + + /* + * TODO: REPLACE + */ + optional sfixed32 longitude_i = 2; + + /* + * In meters above MSL (but see issue #359) + */ + optional int32 altitude = 3; + + /* + * This is usually not sent over the mesh (to save space), but it is sent + * from the phone so that the local device can set its time if it is sent over + * the mesh (because there are devices on the mesh without GPS or RTC). + * seconds since 1970 + */ + fixed32 time = 4; + + /* + * How the location was acquired: manual, onboard GPS, external (EUD) GPS + */ + enum LocSource { + /* + * TODO: REPLACE + */ + LOC_UNSET = 0; + + /* + * TODO: REPLACE + */ + LOC_MANUAL = 1; + + /* + * TODO: REPLACE + */ + LOC_INTERNAL = 2; + + /* + * TODO: REPLACE + */ + LOC_EXTERNAL = 3; + } + + /* + * TODO: REPLACE + */ + LocSource location_source = 5; + + /* + * How the altitude was acquired: manual, GPS int/ext, etc + * Default: same as location_source if present + */ + enum AltSource { + /* + * TODO: REPLACE + */ + ALT_UNSET = 0; + + /* + * TODO: REPLACE + */ + ALT_MANUAL = 1; + + /* + * TODO: REPLACE + */ + ALT_INTERNAL = 2; + + /* + * TODO: REPLACE + */ + ALT_EXTERNAL = 3; + + /* + * TODO: REPLACE + */ + ALT_BAROMETRIC = 4; + } + + /* + * TODO: REPLACE + */ + AltSource altitude_source = 6; + + /* + * Positional timestamp (actual timestamp of GPS solution) in integer epoch seconds + */ + fixed32 timestamp = 7; + + /* + * Pos. timestamp milliseconds adjustment (rarely available or required) + */ + int32 timestamp_millis_adjust = 8; + + /* + * HAE altitude in meters - can be used instead of MSL altitude + */ + optional sint32 altitude_hae = 9; + + /* + * Geoidal separation in meters + */ + optional sint32 altitude_geoidal_separation = 10; + + /* + * Horizontal, Vertical and Position Dilution of Precision, in 1/100 units + * - PDOP is sufficient for most cases + * - for higher precision scenarios, HDOP and VDOP can be used instead, + * in which case PDOP becomes redundant (PDOP=sqrt(HDOP^2 + VDOP^2)) + * TODO: REMOVE/INTEGRATE + */ + uint32 PDOP = 11; + + /* + * TODO: REPLACE + */ + uint32 HDOP = 12; + + /* + * TODO: REPLACE + */ + uint32 VDOP = 13; + + /* + * GPS accuracy (a hardware specific constant) in mm + * multiplied with DOP to calculate positional accuracy + * Default: "'bout three meters-ish" :) + */ + uint32 gps_accuracy = 14; + + /* + * Ground speed in m/s 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) + * - "yaw" indicates a relative rotation about the vertical axis + * TODO: REMOVE/INTEGRATE + */ + optional uint32 ground_speed = 15; + + /* + * TODO: REPLACE + */ + optional uint32 ground_track = 16; + + /* + * GPS fix quality (from NMEA GxGGA statement or similar) + */ + uint32 fix_quality = 17; + + /* + * GPS fix type 2D/3D (from NMEA GxGSA statement) + */ + uint32 fix_type = 18; + + /* + * GPS "Satellites in View" number + */ + uint32 sats_in_view = 19; + + /* + * Sensor ID - in case multiple positioning sensors are being used + */ + uint32 sensor_id = 20; + + /* + * Estimated/expected time (in seconds) until next update: + * - if we update at fixed intervals of X seconds, use X + * - if we update at dynamic intervals (based on relative movement etc), + * but "AT LEAST every Y seconds", use Y + */ + uint32 next_update = 21; + + /* + * A sequence number, incremented with each Position message to help + * detect lost updates if needed + */ + uint32 seq_number = 22; + + /* + * Indicates the bits of precision set by the sending node + */ + uint32 precision_bits = 23; +} + +/* + * Note: these enum names must EXACTLY match the string used in the device + * bin/build-all.sh script. + * Because they will be used to find firmware filenames in the android app for OTA updates. + * To match the old style filenames, _ is converted to -, p is converted to . + */ +enum HardwareModel { + /* + * TODO: REPLACE + */ + UNSET = 0; + + /* + * TODO: REPLACE + */ + TLORA_V2 = 1; + + /* + * TODO: REPLACE + */ + TLORA_V1 = 2; + + /* + * TODO: REPLACE + */ + TLORA_V2_1_1P6 = 3; + + /* + * TODO: REPLACE + */ + TBEAM = 4; + + /* + * The original heltec WiFi_Lora_32_V2, which had battery voltage sensing hooked to GPIO 13 + * (see HELTEC_V2 for the new version). + */ + HELTEC_V2_0 = 5; + + /* + * TODO: REPLACE + */ + TBEAM_V0P7 = 6; + + /* + * TODO: REPLACE + */ + T_ECHO = 7; + + /* + * TODO: REPLACE + */ + TLORA_V1_1P3 = 8; + + /* + * TODO: REPLACE + */ + RAK4631 = 9; + + /* + * The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37. + * Sadly they did not update anything on the silkscreen to identify this board + */ + HELTEC_V2_1 = 10; + + /* + * Ancient heltec WiFi_Lora_32 board + */ + HELTEC_V1 = 11; + + /* + * New T-BEAM with ESP32-S3 CPU + */ + LILYGO_TBEAM_S3_CORE = 12; + + /* + * RAK WisBlock ESP32 core: https://docs.rakwireless.com/Product-Categories/WisBlock/RAK11200/Overview/ + */ + RAK11200 = 13; + + /* + * B&Q Consulting Nano Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:nano + */ + NANO_G1 = 14; + + /* + * TODO: REPLACE + */ + TLORA_V2_1_1P8 = 15; + + /* + * TODO: REPLACE + */ + TLORA_T3_S3 = 16; + + /* + * B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer + */ + NANO_G1_EXPLORER = 17; + + /* + * B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra + */ + NANO_G2_ULTRA = 18; + + /* + * LoRAType device: https://loratype.org/ + */ + LORA_TYPE = 19; + + /* + * wiphone https://www.wiphone.io/ + */ + WIPHONE = 20; + + /* + * WIO Tracker WM1110 family from Seeed Studio. Includes wio-1110-tracker and wio-1110-sdk + */ + WIO_WM1110 = 21; + + /* + * RAK2560 Solar base station based on RAK4630 + */ + RAK2560 = 22; + + /* + * Heltec HRU-3601: https://heltec.org/project/hru-3601/ + */ + HELTEC_HRU_3601 = 23; + + /* + * Heltec Wireless Bridge + */ + HELTEC_WIRELESS_BRIDGE = 24; + + /* + * B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station + */ + STATION_G1 = 25; + + /* + * RAK11310 (RP2040 + SX1262) + */ + RAK11310 = 26; + + /* + * Makerfabs SenseLoRA Receiver (RP2040 + RFM96) + */ + SENSELORA_RP2040 = 27; + + /* + * Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96) + */ + SENSELORA_S3 = 28; + + /* + * Canary Radio Company - CanaryOne: https://canaryradio.io/products/canaryone + */ + CANARYONE = 29; + + /* + * Waveshare RP2040 LoRa - https://www.waveshare.com/rp2040-lora.htm + */ + RP2040_LORA = 30; + + /* + * B&Q Consulting Station G2: https://wiki.uniteng.com/en/meshtastic/station-g2 + */ + STATION_G2 = 31; + + /* + * --------------------------------------------------------------------------- + * Less common/prototype boards listed here (needs one more byte over the air) + * --------------------------------------------------------------------------- + */ + LORA_RELAY_V1 = 32; + + /* + * TODO: REPLACE + */ + NRF52840DK = 33; + + /* + * TODO: REPLACE + */ + PPR = 34; + + /* + * TODO: REPLACE + */ + GENIEBLOCKS = 35; + + /* + * TODO: REPLACE + */ + NRF52_UNKNOWN = 36; + + /* + * TODO: REPLACE + */ + PORTDUINO = 37; + + /* + * The simulator built into the android app + */ + ANDROID_SIM = 38; + + /* + * Custom DIY device based on @NanoVHF schematics: https://github.com/NanoVHF/Meshtastic-DIY/tree/main/Schematics + */ + DIY_V1 = 39; + + /* + * nRF52840 Dongle : https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle/ + */ + NRF52840_PCA10059 = 40; + + /* + * Custom Disaster Radio esp32 v3 device https://github.com/sudomesh/disaster-radio/tree/master/hardware/board_esp32_v3 + */ + DR_DEV = 41; + + /* + * M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ + */ + M5STACK = 42; + + /* + * New Heltec LoRA32 with ESP32-S3 CPU + */ + HELTEC_V3 = 43; + + /* + * New Heltec Wireless Stick Lite with ESP32-S3 CPU + */ + HELTEC_WSL_V3 = 44; + + /* + * New BETAFPV ELRS Micro TX Module 2.4G with ESP32 CPU + */ + BETAFPV_2400_TX = 45; + + /* + * BetaFPV ExpressLRS "Nano" TX Module 900MHz with ESP32 CPU + */ + BETAFPV_900_NANO_TX = 46; + + /* + * Raspberry Pi Pico (W) with Waveshare SX1262 LoRa Node Module + */ + RPI_PICO = 47; + + /* + * Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT + * Newer V1.1, version is written on the PCB near the display. + */ + HELTEC_WIRELESS_TRACKER = 48; + + /* + * Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display + */ + HELTEC_WIRELESS_PAPER = 49; + + /* + * LilyGo T-Deck with ESP32-S3 CPU, Keyboard and IPS display + */ + T_DECK = 50; + + /* + * LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display + */ + T_WATCH_S3 = 51; + + /* + * Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display + */ + PICOMPUTER_S3 = 52; + + /* + * Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa + */ + HELTEC_HT62 = 53; + + /* + * EBYTE SPI LoRa module and ESP32-S3 + */ + EBYTE_ESP32_S3 = 54; + + /* + * Waveshare ESP32-S3-PICO with PICO LoRa HAT and 2.9inch e-Ink + */ + ESP32_S3_PICO = 55; + + /* + * CircuitMess Chatter 2 LLCC68 Lora Module and ESP32 Wroom + * Lora module can be swapped out for a Heltec RA-62 which is "almost" pin compatible + * with one cut and one jumper Meshtastic works + */ + CHATTER_2 = 56; + + /* + * Heltec Wireless Paper, With ESP32-S3 CPU and E-Ink display + * Older "V1.0" Variant, has no "version sticker" + * E-Ink model is DEPG0213BNS800 + * Tab on the screen protector is RED + * Flex connector marking is FPC-7528B + */ + HELTEC_WIRELESS_PAPER_V1_0 = 57; + + /* + * Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT + * Older "V1.0" Variant + */ + HELTEC_WIRELESS_TRACKER_V1_0 = 58; + + /* + * unPhone with ESP32-S3, TFT touchscreen, LSM6DS3TR-C accelerometer and gyroscope + */ + UNPHONE = 59; + + /* + * Teledatics TD-LORAC NRF52840 based M.2 LoRA module + * Compatible with the TD-WRLS development board + */ + TD_LORAC = 60; + + /* + * CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 + */ + CDEBYTE_EORA_S3 = 61; + + /* + * TWC_MESH_V4 + * Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS + */ + TWC_MESH_V4 = 62; + + /* + * NRF52_PROMICRO_DIY + * Promicro NRF52840 with SX1262/LLCC68, SSD1306 OLED and NEO6M GPS + */ + NRF52_PROMICRO_DIY = 63; + + /* + * RadioMaster 900 Bandit Nano, https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module + * ESP32-D0WDQ6 With SX1276/SKY66122, SSD1306 OLED and No GPS + */ + RADIOMASTER_900_BANDIT_NANO = 64; + + /* + * Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors + */ + HELTEC_CAPSULE_SENSOR_V3 = 65; + + /* + * Heltec Vision Master T190 with ESP32-S3 CPU, and a 1.90 inch TFT display + */ + HELTEC_VISION_MASTER_T190 = 66; + + /* + * Heltec Vision Master E213 with ESP32-S3 CPU, and a 2.13 inch E-Ink display + */ + HELTEC_VISION_MASTER_E213 = 67; + + /* + * Heltec Vision Master E290 with ESP32-S3 CPU, and a 2.9 inch E-Ink display + */ + HELTEC_VISION_MASTER_E290 = 68; + + /* + * Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, + * specifically adapted for the Meshtatic project + */ + HELTEC_MESH_NODE_T114 = 69; + + /* + * Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor + */ + SENSECAP_INDICATOR = 70; + + /* + * Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. + */ + TRACKER_T1000_E = 71; + + /* + * RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) + */ + RAK3172 = 72; + + /* + * Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. + */ + WIO_E5 = 73; + + /* + * RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module + * SSD1306 OLED and No GPS + */ + RADIOMASTER_900_BANDIT = 74; + + /* + * Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. + */ + ME25LS01_4Y10TD = 75; + + /* + * RP2040_FEATHER_RFM95 + * Adafruit Feather RP2040 with RFM95 LoRa Radio RFM95 with SX1272, SSD1306 OLED + * https://www.adafruit.com/product/5714 + * https://www.adafruit.com/product/326 + * https://www.adafruit.com/product/938 + * ^^^ short A0 to switch to I2C address 0x3C + * + */ + RP2040_FEATHER_RFM95 = 76; + + /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */ + M5STACK_COREBASIC = 77; + M5STACK_CORE2 = 78; + + /* Pico2 with Waveshare Hat, same as Pico */ + RPI_PICO2 = 79; + + /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */ + M5STACK_CORES3 = 80; + + /* Seeed XIAO S3 DK*/ + SEEED_XIAO_S3 = 81; + + /* + * Nordic nRF52840+Semtech SX1262 LoRa BLE Combo Module. nRF52840+SX1262 MS24SF1 + */ + MS24SF1 = 82; + + /* + * Lilygo TLora-C6 with the new ESP32-C6 MCU + */ + TLORA_C6 = 83; + + /* + * WisMesh Tap + * RAK-4631 w/ TFT in injection modled case + */ + WISMESH_TAP = 84; + + /* + * Similar to PORTDUINO but used by Routastic devices, this is not any + * particular device and does not run Meshtastic's code but supports + * the same frame format. + * Runs on linux, see https://github.com/Jorropo/routastic + */ + ROUTASTIC = 85; + + /* + * Mesh-Tab, esp32 based + * https://github.com/valzzu/Mesh-Tab + */ + MESH_TAB = 86; + + /* + * MeshLink board developed by LoraItalia. NRF52840, eByte E22900M22S (Will also come with other frequencies), 25w MPPT solar charger (5v,12v,18v selectable), support for gps, buzzer, oled or e-ink display, 10 gpios, hardware watchdog + * https://www.loraitalia.it + */ + MESHLINK = 87; + + /* + * Seeed XIAO nRF52840 + Wio SX1262 kit + */ + XIAO_NRF52_KIT = 88; + + /* + * Elecrow ThinkNode M1 & M2 + * https://www.elecrow.com/wiki/ThinkNode-M1_Transceiver_Device(Meshtastic)_Power_By_nRF52840.html + * https://www.elecrow.com/wiki/ThinkNode-M2_Transceiver_Device(Meshtastic)_Power_By_NRF52840.html (this actually uses ESP32-S3) + */ + THINKNODE_M1 = 89; + THINKNODE_M2 = 90; + + /* + * Lilygo T-ETH-Elite + */ + T_ETH_ELITE = 91; + + /* + * Heltec HRI-3621 industrial probe + */ + HELTEC_SENSOR_HUB = 92; + + /* + * Reserved Fried Chicken ID for future use + */ + RESERVED_FRIED_CHICKEN = 93; + + /* + * Heltec Magnetic Power Bank with Meshtastic compatible + */ + HELTEC_MESH_POCKET = 94; + + /* + * Seeed Solar Node + */ + SEEED_SOLAR_NODE = 95; + + /* + * NomadStar Meteor Pro https://nomadstar.ch/ + */ + NOMADSTAR_METEOR_PRO = 96; + + /* + * Elecrow CrowPanel Advance models, ESP32-S3 and TFT with SX1262 radio plugin + */ + CROWPANEL = 97; + + /* + * Lilygo LINK32 board with sensors + */ + LINK_32 = 98; + + /* + * Seeed Tracker L1 + */ + SEEED_WIO_TRACKER_L1 = 99; + + /* + * Seeed Tracker L1 EINK driver + */ + SEEED_WIO_TRACKER_L1_EINK = 100; + + /* + * Muzi Works R1 Neo + */ + MUZI_R1_NEO = 101; + + /* + * Lilygo T-Deck Pro + */ + T_DECK_PRO = 102; + + /* + * Lilygo TLora Pager + */ + T_LORA_PAGER = 103; + + /* + * M5Stack Reserved + */ + M5STACK_RESERVED = 104; // 0x68 + + /* + * RAKwireless WisMesh Tag + */ + WISMESH_TAG = 105; + + /* + * RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ + */ + RAK3312 = 106; + + /* + * Elecrow ThinkNode M5 https://www.elecrow.com/wiki/ThinkNode_M5_Meshtastic_LoRa_Signal_Transceiver_ESP32-S3.html + */ + THINKNODE_M5 = 107; + + /* + * MeshSolar is an integrated power management and communication solution designed for outdoor low-power devices. + * https://heltec.org/project/meshsolar/ + */ + HELTEC_MESH_SOLAR = 108; + + /* + * Lilygo T-Echo Lite + */ + T_ECHO_LITE = 109; + + /* + * New Heltec LoRA32 with ESP32-S3 CPU + */ + HELTEC_V4 = 110; + + /* + * M5Stack C6L + */ + M5STACK_C6L = 111; + + /* + * M5Stack Cardputer Adv + */ + M5STACK_CARDPUTER_ADV = 112; + + /* + * ESP32S3 main controller with GPS and TFT screen. + */ + HELTEC_WIRELESS_TRACKER_V2 = 113; + + /* + * LilyGo T-Watch Ultra + */ + T_WATCH_ULTRA = 114; + + /* + * ------------------------------------------------------------------------------------------------------------------------------------------ + * 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. + * ------------------------------------------------------------------------------------------------------------------------------------------ + */ + PRIVATE_HW = 255; +} + +/* + * Broadcast when a newly powered mesh node wants to find a node num it can use + * Sent from the phone over bluetooth to set the user id for the owner of this node. + * Also sent from nodes to each other when a new node signs on (so all clients can have this info) + * The algorithm is as follows: + * when a node starts up, it broadcasts their user and the normal flow is for all + * other nodes to reply with their User as well (so the new node can build its nodedb) + * If a node ever receives a User (not just the first broadcast) message where + * the sender node number equals our node number, that indicates a collision has + * occurred and the following steps should happen: + * If the receiving node (that was already in the mesh)'s macaddr is LOWER than the + * new User who just tried to sign in: it gets to keep its nodenum. + * We send a broadcast message of OUR User (we use a broadcast so that the other node can + * receive our message, considering we have the same id - it also serves to let + * observers correct their nodedb) - this case is rare so it should be okay. + * If any node receives a User where the macaddr is GTE than their local macaddr, + * they have been vetoed and should pick a new random nodenum (filtering against + * whatever it knows about the nodedb) and rebroadcast their User. + * A few nodenums are reserved and will never be requested: + * 0xff - broadcast + * 0 through 3 - for future use + */ +message User { + /* + * A globally unique ID string for this user. + * In the case of Signal that would mean +16504442323, for the default macaddr derived id it would be !<8 hexidecimal bytes>. + * Note: app developers are encouraged to also use the following standard + * node IDs "^all" (for broadcast), "^local" (for the locally connected node) + */ + string id = 1; + + /* + * A full name for this user, i.e. "Kevin Hester" + */ + string long_name = 2; + + /* + * A VERY short name, ideally two characters. + * Suitable for a tiny OLED screen + */ + string short_name = 3; + + /* + * Deprecated in Meshtastic 2.1.x + * This is the addr of the radio. + * Not populated by the phone, but added by the esp32 when broadcasting + */ + bytes macaddr = 4 [deprecated = true]; + + /* + * TBEAM, HELTEC, etc... + * Starting in 1.2.11 moved to hw_model enum in the NodeInfo object. + * Apps will still need the string here for older builds + * (so OTA update can find the right image), but if the enum is available it will be used instead. + */ + HardwareModel hw_model = 5; + + /* + * In some regions Ham radio operators have different bandwidth limitations than others. + * If this user is a licensed operator, set this flag. + * Also, "long_name" should be their licence number. + */ + bool is_licensed = 6; + + /* + * Indicates that the user's role in the mesh + */ + Config.DeviceConfig.Role role = 7; + + /* + * The public key of the user's device. + * This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + */ + bytes public_key = 8; + + /* + * Whether or not the node can be messaged + */ + optional bool is_unmessagable = 9; +} + +/* + * A message used in a traceroute + */ +message RouteDiscovery { + /* + * The list of nodenums this packet has visited so far to the destination. + */ + repeated fixed32 route = 1; + + /* + * The list of SNRs (in dB, scaled by 4) in the route towards the destination. + */ + repeated int32 snr_towards = 2; + + /* + * The list of nodenums the packet has visited on the way back from the destination. + */ + repeated fixed32 route_back = 3; + + /* + * The list of SNRs (in dB, scaled by 4) in the route back from the destination. + */ + repeated int32 snr_back = 4; +} + +/* + * A Routing control Data packet handled by the routing module + */ +message Routing { + /* + * A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide + * details on the type of failure). + */ + enum Error { + /* + * This message is not a failure + */ + NONE = 0; + + /* + * Our node doesn't have a route to the requested destination anymore. + */ + NO_ROUTE = 1; + + /* + * We received a nak while trying to forward on your behalf + */ + GOT_NAK = 2; + + /* + * TODO: REPLACE + */ + TIMEOUT = 3; + + /* + * No suitable interface could be found for delivering this packet + */ + NO_INTERFACE = 4; + + /* + * We reached the max retransmission count (typically for naive flood routing) + */ + MAX_RETRANSMIT = 5; + + /* + * No suitable channel was found for sending this packet (i.e. was requested channel index disabled?) + */ + NO_CHANNEL = 6; + + /* + * The packet was too big for sending (exceeds interface MTU after encoding) + */ + TOO_LARGE = 7; + + /* + * The request had want_response set, the request reached the destination node, but no service on that node wants to send a response + * (possibly due to bad channel permissions) + */ + NO_RESPONSE = 8; + + /* + * Cannot send currently because duty cycle regulations will be violated. + */ + DUTY_CYCLE_LIMIT = 9; + + /* + * The application layer service on the remote node received your request, but considered your request somehow invalid + */ + BAD_REQUEST = 32; + + /* + * The application layer service on the remote node received your request, but considered your request not authorized + * (i.e you did not send the request on the required bound channel) + */ + NOT_AUTHORIZED = 33; + + /* + * The client specified a PKI transport, but the node was unable to send the packet using PKI (and did not send the message at all) + */ + PKI_FAILED = 34; + + /* + * The receiving node does not have a Public Key to decode with + */ + PKI_UNKNOWN_PUBKEY = 35; + + /* + * Admin packet otherwise checks out, but uses a bogus or expired session key + */ + ADMIN_BAD_SESSION_KEY = 36; + + /* + * Admin packet sent using PKC, but not from a public key on the admin key list + */ + ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37; + + /* + * Airtime fairness rate limit exceeded for a packet + * This typically enforced per portnum and is used to prevent a single node from monopolizing airtime + */ + RATE_LIMIT_EXCEEDED = 38; + } + + oneof variant { + /* + * A route request going from the requester + */ + RouteDiscovery route_request = 1; + + /* + * A route reply + */ + RouteDiscovery route_reply = 2; + + /* + * A failure in delivering a message (usually used for routing control messages, but might be provided + * in addition to ack.fail_id to provide details on the type of failure). + */ + Error error_reason = 3; + } +} + +/* + * (Formerly called SubPacket) + * The payload portion fo a packet, this is the actual bytes that are sent + * inside a radio packet (because from/to are broken out by the comms library) + */ +message Data { + /* + * Formerly named typ and of type Type + */ + PortNum portnum = 1; + + /* + * TODO: REPLACE + */ + bytes payload = 2; + + /* + * Not normally used, but for testing a sender can request that recipient + * responds in kind (i.e. if it received a position, it should unicast back it's position). + * Note: that if you set this on a broadcast you will receive many replies. + */ + bool want_response = 3; + + /* + * The address of the destination node. + * This field is is filled in by the mesh radio device software, application + * layer software should never need it. + * RouteDiscovery messages _must_ populate this. + * Other message types might need to if they are doing multihop routing. + */ + fixed32 dest = 4; + + /* + * The address of the original sender for this message. + * This field should _only_ be populated for reliable multihop packets (to keep + * packets small). + */ + fixed32 source = 5; + + /* + * Only used in routing or response messages. + * Indicates the original message ID that this message is reporting failure on. (formerly called original_id) + */ + fixed32 request_id = 6; + + /* + * If set, this message is intened to be a reply to a previously sent message with the defined id. + */ + fixed32 reply_id = 7; + + /* + * Defaults to false. If true, then what is in the payload should be treated as an emoji like giving + * a message a heart or poop emoji. + */ + fixed32 emoji = 8; + + /* + * Bitfield for extra flags. First use is to indicate that user approves the packet being uploaded to MQTT. + */ + optional uint32 bitfield = 9; +} + +/* + * The actual over-the-mesh message doing KeyVerification + */ +message KeyVerification { + /* + * random value Selected by the requesting node + */ + uint64 nonce = 1; + + /* + * The final authoritative hash, only to be sent by NodeA at the end of the handshake + */ + bytes hash1 = 2; + + /* + * The intermediary hash (actually derived from hash1), + * sent from NodeB to NodeA in response to the initial message. + */ + bytes hash2 = 3; +} + +/* + * Waypoint message, used to share arbitrary locations across the mesh + */ +message Waypoint { + /* + * Id of the waypoint + */ + uint32 id = 1; + + /* + * latitude_i + */ + optional sfixed32 latitude_i = 2; + + /* + * longitude_i + */ + optional sfixed32 longitude_i = 3; + + /* + * Time the waypoint is to expire (epoch) + */ + uint32 expire = 4; + + /* + * If greater than zero, treat the value as a nodenum only allowing them to update the waypoint. + * If zero, the waypoint is open to be edited by any member of the mesh. + */ + uint32 locked_to = 5; + + /* + * Name of the waypoint - max 30 chars + */ + string name = 6; + + /* + * Description of the waypoint - max 100 chars + */ + string description = 7; + + /* + * Designator icon for the waypoint in the form of a unicode emoji + */ + fixed32 icon = 8; +} + +/* + * This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server + */ +message MqttClientProxyMessage { + /* + * The MQTT topic this message will be sent /received on + */ + string topic = 1; + + /* + * The actual service envelope payload or text for mqtt pub / sub + */ + oneof payload_variant { + /* + * Bytes + */ + bytes data = 2; + + /* + * Text + */ + string text = 3; + } + + /* + * Whether the message should be retained (or not) + */ + bool retained = 4; +} + +/* + * A packet envelope sent/received over the mesh + * only payload_variant is sent in the payload portion of the LORA packet. + * The other fields are either not sent at all, or sent in the special 16 byte LORA header. + */ +message MeshPacket { + /* + * The priority of this message for sending. + * Higher priorities are sent first (when managing the transmit queue). + * This field is never sent over the air, it is only used internally inside of a local device node. + * API clients (either on the local node or connected directly to the node) + * can set this parameter if necessary. + * (values must be <= 127 to keep protobuf field to one byte in size. + * Detailed background on this field: + * I noticed a funny side effect of lora being so slow: Usually when making + * a protocol there isn’t much need to use message priority to change the order + * of transmission (because interfaces are fairly fast). + * But for lora where packets can take a few seconds each, it is very important + * to make sure that critical packets are sent ASAP. + * In the case of meshtastic that means we want to send protocol acks as soon as possible + * (to prevent unneeded retransmissions), we want routing messages to be sent next, + * then messages marked as reliable and finally 'background' packets like periodic position updates. + * So I bit the bullet and implemented a new (internal - not sent over the air) + * field in MeshPacket called 'priority'. + * And the transmission queue in the router object is now a priority queue. + */ + enum Priority { + /* + * Treated as Priority.DEFAULT + */ + UNSET = 0; + + /* + * TODO: REPLACE + */ + MIN = 1; + + /* + * Background position updates are sent with very low priority - + * if the link is super congested they might not go out at all + */ + BACKGROUND = 10; + + /* + * This priority is used for most messages that don't have a priority set + */ + DEFAULT = 64; + + /* + * If priority is unset but the message is marked as want_ack, + * assume it is important and use a slightly higher priority + */ + RELIABLE = 70; + + /* + * If priority is unset but the packet is a response to a request, we want it to get there relatively quickly. + * Furthermore, responses stop relaying packets directed to a node early. + */ + RESPONSE = 80; + + /* + * Higher priority for specific message types (portnums) to distinguish between other reliable packets. + */ + HIGH = 100; + + /* + * Higher priority alert message used for critical alerts which take priority over other reliable packets. + */ + ALERT = 110; + + /* + * Ack/naks are sent with very high priority to ensure that retransmission + * stops as soon as possible + */ + ACK = 120; + + /* + * TODO: REPLACE + */ + MAX = 127; + } + + /* + * Identify if this is a delayed packet + */ + enum Delayed { + /* + * If unset, the message is being sent in real time. + */ + NO_DELAY = 0; + + /* + * The message is delayed and was originally a broadcast + */ + DELAYED_BROADCAST = 1; + + /* + * The message is delayed and was originally a direct message + */ + DELAYED_DIRECT = 2; + } + + /* + * Enum to identify which transport mechanism this packet arrived over + */ + enum TransportMechanism { + /* + * The default case is that the node generated a packet itself + */ + TRANSPORT_INTERNAL = 0; + + /* + * Arrived via the primary LoRa radio + */ + TRANSPORT_LORA = 1; + + /* + * Arrived via a secondary LoRa radio + */ + TRANSPORT_LORA_ALT1 = 2; + + /* + * Arrived via a tertiary LoRa radio + */ + TRANSPORT_LORA_ALT2 = 3; + + /* + * Arrived via a quaternary LoRa radio + */ + TRANSPORT_LORA_ALT3 = 4; + + /* + * Arrived via an MQTT connection + */ + TRANSPORT_MQTT = 5; + + /* + * Arrived via Multicast UDP + */ + TRANSPORT_MULTICAST_UDP = 6; + + /* + * Arrived via API connection + */ + TRANSPORT_API = 7; + } + + /* + * The sending node number. + * Note: Our crypto implementation uses this field as well. + * See [crypto](/docs/overview/encryption) for details. + */ + fixed32 from = 1; + + /* + * The (immediate) destination for this packet + */ + fixed32 to = 2; + + /* + * (Usually) If set, this indicates the index in the secondary_channels table that this packet was sent/received on. + * If unset, packet was on the primary channel. + * A particular node might know only a subset of channels in use on the mesh. + * Therefore channel_index is inherently a local concept and meaningless to send between nodes. + * Very briefly, while sending and receiving deep inside the device Router code, this field instead + * contains the 'channel hash' instead of the index. + * This 'trick' is only used while the payload_variant is an 'encrypted'. + */ + uint32 channel = 3; + + /* + * Internally to the mesh radios we will route SubPackets encrypted per [this](docs/developers/firmware/encryption). + * However, when a particular node has the correct + * key to decode a particular packet, it will decode the payload into a SubPacket protobuf structure. + * Software outside of the device nodes will never encounter a packet where + * "decoded" is not populated (i.e. any encryption/decryption happens before reaching the applications) + * The numeric IDs for these fields were selected to keep backwards compatibility with old applications. + */ + + oneof payload_variant { + /* + * TODO: REPLACE + */ + Data decoded = 4; + + /* + * TODO: REPLACE + */ + bytes encrypted = 5; + } + + /* + * A unique ID for this packet. + * Always 0 for no-ack packets or non broadcast packets (and therefore take zero bytes of space). + * Otherwise a unique ID for this packet, useful for flooding algorithms. + * ID only needs to be unique on a _per sender_ basis, and it only + * needs to be unique for a few minutes (long enough to last for the length of + * any ACK or the completion of a mesh broadcast flood). + * Note: Our crypto implementation uses this id as well. + * See [crypto](/docs/overview/encryption) for details. + */ + fixed32 id = 6; + + /* + * The time this message was received by the esp32 (secs since 1970). + * 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; + + /* + * *Never* sent over the radio links. + * Set during reception to indicate the SNR of this packet. + * Used to collect statistics on current link quality. + */ + float rx_snr = 8; + + /* + * If unset treated as zero (no forwarding, send to direct neighbor nodes only) + * if 1, allow hopping through one node, etc... + * For our usecase real world topologies probably have a max of about 3. + * This field is normally placed into a few of bits in the header. + */ + uint32 hop_limit = 9; + + /* + * This packet is being sent as a reliable message, we would prefer it to arrive at the destination. + * We would like to receive a ack packet in response. + * Broadcasts messages treat this flag specially: Since acks for broadcasts would + * rapidly flood the channel, the normal ack behavior is suppressed. + * Instead, the original sender listens to see if at least one node is rebroadcasting this packet (because naive flooding algorithm). + * If it hears that the odds (given typical LoRa topologies) the odds are very high that every node should eventually receive the message. + * So FloodingRouter.cpp generates an implicit ack which is delivered to the original sender. + * If after some time we don't hear anyone rebroadcast our packet, we will timeout and retransmit, using the regular resend logic. + * Note: This flag is normally sent in a flag bit in the header when sent over the wire + */ + bool want_ack = 10; + + /* + * The priority of this message for sending. + * See MeshPacket.Priority description for more details. + */ + Priority priority = 11; + + /* + * rssi of received packet. Only sent to phone for dispay purposes. + */ + int32 rx_rssi = 12; + + /* + * Describe if this message is delayed + */ + Delayed delayed = 13 [deprecated = true]; + + /* + * Describes whether this packet passed via MQTT somewhere along the path it currently took. + */ + bool via_mqtt = 14; + + /* + * 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. + */ + uint32 hop_start = 15; + + /* + * Records the public key the packet was encrypted with, if applicable. + */ + bytes public_key = 16; + + /* + * Indicates whether the packet was en/decrypted using PKI + */ + bool pki_encrypted = 17; + + /* + * Last byte of the node number of the node that should be used as the next hop in routing. + * Set by the firmware internally, clients are not supposed to set this. + */ + uint32 next_hop = 18; + + /* + * Last byte of the node number of the node that will relay/relayed this packet. + * Set by the firmware internally, clients are not supposed to set this. + */ + uint32 relay_node = 19; + + /* + * *Never* sent over the radio links. + * Timestamp after which this packet may be sent. + * Set by the firmware internally, clients are not supposed to set this. + */ + uint32 tx_after = 20; + + /* + * Indicates which transport mechanism this packet arrived over + */ + TransportMechanism transport_mechanism = 21; +} + +/* + * Shared constants between device and phone + */ +enum Constants { + /* + * First enum must be zero, and we are just using this enum to + * pass int constants between two very different environments + */ + ZERO = 0; + + /* + * From mesh.options + * note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is + * outside of this envelope + */ + DATA_PAYLOAD_LEN = 233; +} + +/* + * The bluetooth to device link: + * Old BTLE protocol docs from TODO, merge in above and make real docs... + * use protocol buffers, and NanoPB + * messages from device to phone: + * POSITION_UPDATE (..., time) + * TEXT_RECEIVED(from, text, time) + * OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications) + * messages from phone to device: + * SET_MYID(id, human readable long, human readable short) (send down the unique ID + * string used for this node, a human readable string shown for that id, and a very + * short human readable string suitable for oled screen) SEND_OPAQUE(dest, payload) + * (for signal messages or other applications) SEND_TEXT(dest, text) Get all + * nodes() (returns list of nodes, with full info, last time seen, loc, battery + * level etc) SET_CONFIG (switches device to a new set of radio params and + * preshared key, drops all existing nodes, force our node to rejoin this new group) + * Full information about a node on the mesh + */ +message NodeInfo { + /* + * The node number + */ + uint32 num = 1; + + /* + * The user info for this node + */ + User user = 2; + + /* + * This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true. + * Position.time now indicates the last time we received a POSITION from that node. + */ + Position position = 3; + + /* + * Returns the Signal-to-noise ratio (SNR) of the last received message, + * as measured by the receiver. Return SNR of the last received message in dB + */ + float snr = 4; + + /* + * TODO: REMOVE/INTEGRATE + * Returns the last measured frequency error. + * The LoRa receiver estimates the frequency offset between the receiver + * center frequency and that of the received LoRa signal. This function + * returns the estimates offset (in Hz) of the last received message. + * Caution: this measurement is not absolute, but is measured relative to the + * local receiver's oscillator. Apparent errors may be due to the + * transmitter, the receiver or both. \return The estimated center frequency + * offset in Hz of the last received message. + * int32 frequency_error = 6; + * enum RouteState { + * Invalid = 0; + * Discovering = 1; + * Valid = 2; + * } + * Not needed? + * RouteState route = 4; + */ + + /* + * TODO: REMOVE/INTEGRATE + * Not currently used (till full DSR deployment?) Our current preferred node node for routing - might be the same as num if + * we are direct neighbor or zero if we don't yet know a route to this node. + * fixed32 next_hop = 5; + */ + + /* + * Set to indicate the last time we received a packet from this node + */ + fixed32 last_heard = 5; + /* + * The latest device metrics for the node. + */ + DeviceMetrics device_metrics = 6; + + /* + * local channel index we heard that node on. Only populated if its not the default channel. + */ + uint32 channel = 7; + + /* + * True if we witnessed the node over MQTT instead of LoRA transport + */ + bool via_mqtt = 8; + + /* + * Number of hops away from us this node is (0 if direct neighbor) + */ + optional uint32 hops_away = 9; + + /* + * True if node is in our favorites list + * Persists between NodeDB internal clean ups + */ + bool is_favorite = 10; + + /* + * True if node is in our ignored list + * Persists between NodeDB internal clean ups + */ + bool is_ignored = 11; + + /* + * True if node public key has been verified. + * Persists between NodeDB internal clean ups + * LSB 0 of the bitfield + */ + bool is_key_manually_verified = 12; +} + +/* + * Error codes for critical errors + * The device might report these fault codes on the screen. + * If you encounter a fault code, please post on the meshtastic.discourse.group + * and we'll try to help. + */ +enum CriticalErrorCode { + /* + * TODO: REPLACE + */ + NONE = 0; + + /* + * A software bug was detected while trying to send lora + */ + TX_WATCHDOG = 1; + + /* + * A software bug was detected on entry to sleep + */ + SLEEP_ENTER_WAIT = 2; + + /* + * No Lora radio hardware could be found + */ + NO_RADIO = 3; + + /* + * Not normally used + */ + UNSPECIFIED = 4; + + /* + * We failed while configuring a UBlox GPS + */ + UBLOX_UNIT_FAILED = 5; + + /* + * This board was expected to have a power management chip and it is missing or broken + */ + NO_AXP192 = 6; + + /* + * The channel tried to set a radio setting which is not supported by this chipset, + * radio comms settings are now undefined. + */ + INVALID_RADIO_SETTING = 7; + + /* + * Radio transmit hardware failure. We sent data to the radio chip, but it didn't + * reply with an interrupt. + */ + TRANSMIT_FAILED = 8; + + /* + * We detected that the main CPU voltage dropped below the minimum acceptable value + */ + BROWNOUT = 9; + + /* Selftest of SX1262 radio chip failed */ + SX1262_FAILURE = 10; + + /* + * A (likely software but possibly hardware) failure was detected while trying to send packets. + * If this occurs on your board, please post in the forum so that we can ask you to collect some information to allow fixing this bug + */ + RADIO_SPI_BUG = 11; + + /* + * Corruption was detected on the flash filesystem but we were able to repair things. + * If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. + */ + FLASH_CORRUPTION_RECOVERABLE = 12; + + /* + * Corruption was detected on the flash filesystem but we were unable to repair things. + * NOTE: Your node will probably need to be reconfigured the next time it reboots (it will lose the region code etc...) + * If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. + */ + FLASH_CORRUPTION_UNRECOVERABLE = 13; +} + +/* + * Enum to indicate to clients whether this firmware is a special firmware build, like an event. + * The first 16 values are reserved for non-event special firmwares, like the Smart Citizen use case. + */ +enum FirmwareEdition { + /* + * Vanilla firmware + */ + VANILLA = 0; + + /* + * Firmware for use in the Smart Citizen environmental monitoring network + */ + SMART_CITIZEN = 1; + + /* + * Open Sauce, the maker conference held yearly in CA + */ + OPEN_SAUCE = 16; + + /* + * DEFCON, the yearly hacker conference + */ + DEFCON = 17; + + /* + * Burning Man, the yearly hippie gathering in the desert + */ + BURNING_MAN = 18; + + /* + * Hamvention, the Dayton amateur radio convention + */ + HAMVENTION = 19; + + /* + * Placeholder for DIY and unofficial events + */ + DIY_EDITION = 127; +} + +/* + * Unique local debugging info for this node + * Note: we don't include position or the user info, because that will come in the + * Sent to the phone in response to WantNodes. + */ +message MyNodeInfo { + /* + * Tells the phone what our node number is, default starting value is + * lowbyte of macaddr, but it will be fixed if that is already in use + */ + uint32 my_node_num = 1; + + /* + * The total number of reboots this node has ever encountered + * (well - since the last time we discarded preferences) + */ + uint32 reboot_count = 8; + + /* + * The minimum app version that can talk to this device. + * Phone/PC apps should compare this to their build number and if too low tell the user they must update their app + */ + uint32 min_app_version = 11; + + /* + * Unique hardware identifier for this device + */ + bytes device_id = 12; + + /* + * The PlatformIO environment used to build this firmware + */ + string pio_env = 13; + + /* + * The indicator for whether this device is running event firmware and which + */ + FirmwareEdition firmware_edition = 14; + + /* + * The number of nodes in the nodedb. + * This is used by the phone to know how many NodeInfo packets to expect on want_config + */ + uint32 nodedb_count = 15; +} + +/* + * Debug output from the device. + * To minimize the size of records inside the device code, if a time/source/level is not set + * on the message it is assumed to be a continuation of the previously sent message. + * This allows the device code to use fixed maxlen 64 byte strings for messages, + * and then extend as needed by emitting multiple records. + */ +message LogRecord { + /* + * Log levels, chosen to match python logging conventions. + */ + enum Level { + /* + * Log levels, chosen to match python logging conventions. + */ + UNSET = 0; + + /* + * Log levels, chosen to match python logging conventions. + */ + CRITICAL = 50; + + /* + * Log levels, chosen to match python logging conventions. + */ + ERROR = 40; + + /* + * Log levels, chosen to match python logging conventions. + */ + WARNING = 30; + + /* + * Log levels, chosen to match python logging conventions. + */ + INFO = 20; + + /* + * Log levels, chosen to match python logging conventions. + */ + DEBUG = 10; + + /* + * Log levels, chosen to match python logging conventions. + */ + TRACE = 5; + } + + /* + * Log levels, chosen to match python logging conventions. + */ + string message = 1; + + /* + * Seconds since 1970 - or 0 for unknown/unset + */ + fixed32 time = 2; + + /* + * Usually based on thread name - if known + */ + string source = 3; + + /* + * Not yet set + */ + Level level = 4; +} + +message QueueStatus { + /* Last attempt to queue status, ErrorCode */ + int32 res = 1; + + /* Free entries in the outgoing queue */ + uint32 free = 2; + + /* Maximum entries in the outgoing queue */ + uint32 maxlen = 3; + + /* What was mesh packet id that generated this response? */ + uint32 mesh_packet_id = 4; +} + +/* + * Packets from the radio to the phone will appear on the fromRadio characteristic. + * It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? + * It will sit in that descriptor until consumed by the phone, + * at which point the next item in the FIFO will be populated. + */ +message FromRadio { + /* + * The packet id, used to allow the phone to request missing read packets from the FIFO, + * see our bluetooth docs + */ + uint32 id = 1; + + /* + * Log levels, chosen to match python logging conventions. + */ + oneof payload_variant { + /* + * Log levels, chosen to match python logging conventions. + */ + MeshPacket packet = 2; + + /* + * Tells the phone what our node number is, can be -1 if we've not yet joined a mesh. + * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. + */ + MyNodeInfo my_info = 3; + + /* + * One packet is sent for each node in the on radio DB + * starts over with the first node in our DB + */ + NodeInfo node_info = 4; + + /* + * Include a part of the config (was: RadioConfig radio) + */ + Config config = 5; + + /* + * Set to send debug console output over our protobuf stream + */ + LogRecord log_record = 6; + + /* + * Sent as true once the device has finished sending all of the responses to want_config + * recipient should check if this ID matches our original request nonce, if + * not, it means your config responses haven't started yet. + * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. + */ + uint32 config_complete_id = 7; + + /* + * Sent to tell clients the radio has just rebooted. + * Set to true if present. + * Not used on all transports, currently just used for the serial console. + * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. + */ + bool rebooted = 8; + + /* + * Include module config + */ + ModuleConfig moduleConfig = 9; + + /* + * One packet is sent for each channel + */ + Channel channel = 10; + + /* + * Queue status info + */ + QueueStatus queueStatus = 11; + + /* + * File Transfer Chunk + */ + XModem xmodemPacket = 12; + + /* + * Device metadata message + */ + DeviceMetadata metadata = 13; + + /* + * MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) + */ + MqttClientProxyMessage mqttClientProxyMessage = 14; + + /* + * File system manifest messages + */ + FileInfo fileInfo = 15; + + /* + * Notification message to the client + */ + ClientNotification clientNotification = 16; + + /* + * Persistent data for device-ui + */ + DeviceUIConfig deviceuiConfig = 17; + } +} + +/* + * A notification message from the device to the client + * To be used for important messages that should to be displayed to the user + * in the form of push notifications or validation messages when saving + * invalid configuration. + */ +message ClientNotification { + /* + * The id of the packet we're notifying in response to + */ + optional uint32 reply_id = 1; + + /* + * Seconds since 1970 - or 0 for unknown/unset + */ + fixed32 time = 2; + + /* + * The level type of notification + */ + LogRecord.Level level = 3; + /* + * The message body of the notification + */ + string message = 4; + + oneof payload_variant { + KeyVerificationNumberInform key_verification_number_inform = 11; + KeyVerificationNumberRequest key_verification_number_request = 12; + KeyVerificationFinal key_verification_final = 13; + DuplicatedPublicKey duplicated_public_key = 14; + LowEntropyKey low_entropy_key = 15; + } +} + +message KeyVerificationNumberInform { + uint64 nonce = 1; + string remote_longname = 2; + uint32 security_number = 3; +} +message KeyVerificationNumberRequest { + uint64 nonce = 1; + string remote_longname = 2; +} +message KeyVerificationFinal { + uint64 nonce = 1; + string remote_longname = 2; + bool isSender = 3; + string verification_characters = 4; +} +message DuplicatedPublicKey {} +message LowEntropyKey {} + +/* + * Individual File info for the device + */ +message FileInfo { + /* + * The fully qualified path of the file + */ + string file_name = 1; + + /* + * The size of the file in bytes + */ + uint32 size_bytes = 2; +} + +/* + * Packets/commands to the radio will be written (reliably) to the toRadio characteristic. + * Once the write completes the phone can assume it is handled. + */ +message ToRadio { + /* + * Log levels, chosen to match python logging conventions. + */ + oneof payload_variant { + /* + * Send this packet on the mesh + */ + MeshPacket packet = 1; + + /* + * Phone wants radio to send full node db to the phone, This is + * typically the first packet sent to the radio when the phone gets a + * bluetooth connection. The radio will respond by sending back a + * MyNodeInfo, a owner, a radio config and a series of + * FromRadio.node_infos, and config_complete + * the integer you write into this field will be reported back in the + * config_complete_id response this allows clients to never be confused by + * a stale old partially sent config. + */ + uint32 want_config_id = 3; + + /* + * Tell API server we are disconnecting now. + * This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link. + * (Sending this message is optional for clients) + */ + bool disconnect = 4; + + /* + * File Transfer Chunk + */ + + XModem xmodemPacket = 5; + + /* + * MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) + */ + MqttClientProxyMessage mqttClientProxyMessage = 6; + + /* + * Heartbeat message (used to keep the device connection awake on serial) + */ + Heartbeat heartbeat = 7; + } +} + +/* + * Compressed message payload + */ +message Compressed { + /* + * PortNum to determine the how to handle the compressed payload. + */ + PortNum portnum = 1; + + /* + * Compressed data. + */ + bytes data = 2; +} + +/* + * Full info on edges for a single node + */ +message NeighborInfo { + /* + * The node ID of the node sending info on its neighbors + */ + uint32 node_id = 1; + /* + * Field to pass neighbor info for the next sending cycle + */ + uint32 last_sent_by_id = 2; + + /* + * Broadcast interval of the represented node (in seconds) + */ + uint32 node_broadcast_interval_secs = 3; + /* + * The list of out edges from this node + */ + repeated Neighbor neighbors = 4; +} + +/* + * A single edge in the mesh + */ +message Neighbor { + /* + * Node ID of neighbor + */ + uint32 node_id = 1; + + /* + * SNR of last heard message + */ + float snr = 2; + + /* + * Reception time (in secs since 1970) of last message that was last sent by this ID. + * Note: this is for local storage only and will not be sent out over the mesh. + */ + fixed32 last_rx_time = 3; + + /* + * Broadcast interval of this neighbor (in seconds). + * Note: this is for local storage only and will not be sent out over the mesh. + */ + uint32 node_broadcast_interval_secs = 4; +} + +/* + * Device metadata response + */ +message DeviceMetadata { + /* + * Device firmware version string + */ + string firmware_version = 1; + + /* + * Device state version + */ + uint32 device_state_version = 2; + + /* + * Indicates whether the device can shutdown CPU natively or via power management chip + */ + bool canShutdown = 3; + + /* + * Indicates that the device has native wifi capability + */ + bool hasWifi = 4; + + /* + * Indicates that the device has native bluetooth capability + */ + bool hasBluetooth = 5; + + /* + * Indicates that the device has an ethernet peripheral + */ + bool hasEthernet = 6; + + /* + * Indicates that the device's role in the mesh + */ + Config.DeviceConfig.Role role = 7; + + /* + * Indicates the device's current enabled position flags + */ + uint32 position_flags = 8; + + /* + * Device hardware model + */ + HardwareModel hw_model = 9; + + /* + * Has Remote Hardware enabled + */ + bool hasRemoteHardware = 10; + + /* + * Has PKC capabilities + */ + bool hasPKC = 11; + + /* + * Bit field of boolean for excluded modules + * (bitwise OR of ExcludedModules) + */ + uint32 excluded_modules = 12; +} + +/* + * Enum for modules excluded from a device's configuration. + * Each value represents a ModuleConfigType that can be toggled as excluded + * by setting its corresponding bit in the `excluded_modules` bitmask field. + */ +enum ExcludedModules { + /* + * Default value of 0 indicates no modules are excluded. + */ + EXCLUDED_NONE = 0x0000; + + /* + * MQTT module + */ + MQTT_CONFIG = 0x0001; + + /* + * Serial module + */ + SERIAL_CONFIG = 0x0002; + + /* + * External Notification module + */ + EXTNOTIF_CONFIG = 0x0004; + + /* + * Store and Forward module + */ + STOREFORWARD_CONFIG = 0x0008; + + /* + * Range Test module + */ + RANGETEST_CONFIG = 0x0010; + + /* + * Telemetry module + */ + TELEMETRY_CONFIG = 0x0020; + + /* + * Canned Message module + */ + CANNEDMSG_CONFIG = 0x0040; + + /* + * Audio module + */ + AUDIO_CONFIG = 0x0080; + + /* + * Remote Hardware module + */ + REMOTEHARDWARE_CONFIG = 0x0100; + + /* + * Neighbor Info module + */ + NEIGHBORINFO_CONFIG = 0x0200; + + /* + * Ambient Lighting module + */ + AMBIENTLIGHTING_CONFIG = 0x0400; + + /* + * Detection Sensor module + */ + DETECTIONSENSOR_CONFIG = 0x0800; + + /* + * Paxcounter module + */ + PAXCOUNTER_CONFIG = 0x1000; + + /* + * Bluetooth config (not technically a module, but used to indicate bluetooth capabilities) + */ + BLUETOOTH_CONFIG = 0x2000; + + /* + * Network config (not technically a module, but used to indicate network capabilities) + */ + NETWORK_CONFIG = 0x4000; +} + +/* + * A heartbeat message is sent to the node from the client to keep the connection alive. + * This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. + */ +message Heartbeat { + /* + * The nonce of the heartbeat message + */ + uint32 nonce = 1; +} + +/* + * RemoteHardwarePins associated with a node + */ +message NodeRemoteHardwarePin { + /* + * The node_num exposing the available gpio pin + */ + uint32 node_num = 1; + + /* + * The the available gpio pin for usage with RemoteHardware module + */ + RemoteHardwarePin pin = 2; +} + +message ChunkedPayload { + /* + * The ID of the entire payload + */ + uint32 payload_id = 1; + + /* + * The total number of chunks in the payload + */ + uint32 chunk_count = 2; + + /* + * The current chunk index in the total + */ + uint32 chunk_index = 3; + + /* + * The binary data of the current chunk + */ + bytes payload_chunk = 4; +} + +/* + * Wrapper message for broken repeated oneof support + */ +message resend_chunks { + repeated uint32 chunks = 1; +} + +/* + * Responses to a ChunkedPayload request + */ +message ChunkedPayloadResponse { + /* + * The ID of the entire payload + */ + uint32 payload_id = 1; + + oneof payload_variant { + /* + * Request to transfer chunked payload + */ + bool request_transfer = 2; + + /* + * Accept the transfer chunked payload + */ + bool accept_transfer = 3; + /* + * Request missing indexes in the chunked payload + */ + resend_chunks resend_chunks = 4; + } +} diff --git a/packages/protobufs/meshtastic/module_config.options b/packages/protobufs/meshtastic/module_config.options new file mode 100644 index 00000000..bf2a5f4b --- /dev/null +++ b/packages/protobufs/meshtastic/module_config.options @@ -0,0 +1,29 @@ +*CannedMessageConfig.allow_input_source max_size:16 + +*MQTTConfig.address max_size:64 +*MQTTConfig.username max_size:64 +*MQTTConfig.password max_size:32 +*MQTTConfig.root max_size:32 + +*AudioConfig.ptt_pin int_size:8 +*AudioConfig.i2s_ws int_size:8 +*AudioConfig.i2s_sd int_size:8 +*AudioConfig.i2s_din int_size:8 +*AudioConfig.i2s_sck int_size:8 + +*ExternalNotificationConfig.output_vibra int_size:8 +*ExternalNotificationConfig.output_buzzer int_size:8 +*ExternalNotificationConfig.nag_timeout int_size:16 + +*RemoteHardwareConfig.available_pins max_count:4 +*RemoteHardwarePin.name max_size:15 +*RemoteHardwarePin.gpio_pin int_size:8 + +*AmbientLightingConfig.current int_size:8 +*AmbientLightingConfig.red int_size:8 +*AmbientLightingConfig.green int_size:8 +*AmbientLightingConfig.blue int_size:8 + +*DetectionSensorConfig.monitor_pin int_size:8 +*DetectionSensorConfig.name max_size:20 +*DetectionSensorConfig.detection_trigger_type max_size:8 diff --git a/packages/protobufs/meshtastic/module_config.proto b/packages/protobufs/meshtastic/module_config.proto new file mode 100644 index 00000000..be8a6937 --- /dev/null +++ b/packages/protobufs/meshtastic/module_config.proto @@ -0,0 +1,870 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "ModuleConfigProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Module Config + */ +message ModuleConfig { + /* + * MQTT Client Config + */ + message MQTTConfig { + /* + * If a meshtastic node is able to reach the internet it will normally attempt to gateway any channels that are marked as + * is_uplink_enabled or is_downlink_enabled. + */ + bool enabled = 1; + + /* + * The server to use for our MQTT global message gateway feature. + * If not set, the default server will be used + */ + string address = 2; + + /* + * MQTT username to use (most useful for a custom MQTT server). + * If using a custom server, this will be honoured even if empty. + * If using the default server, this will only be honoured if set, otherwise the device will use the default username + */ + string username = 3; + + /* + * MQTT password to use (most useful for a custom MQTT server). + * If using a custom server, this will be honoured even if empty. + * If using the default server, this will only be honoured if set, otherwise the device will use the default password + */ + string password = 4; + + /* + * Whether to send encrypted or decrypted packets to MQTT. + * This parameter is only honoured if you also set server + * (the default official mqtt.meshtastic.org server can handle encrypted packets) + * Decrypted packets may be useful for external systems that want to consume meshtastic packets + */ + bool encryption_enabled = 5; + + /* + * Whether to send / consume json packets on MQTT + */ + bool json_enabled = 6; + + /* + * If true, we attempt to establish a secure connection using TLS + */ + bool tls_enabled = 7; + + /* + * The root topic to use for MQTT messages. Default is "msh". + * This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs + */ + string root = 8; + + /* + * If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection + */ + bool proxy_to_client_enabled = 9; + + /* + * If true, we will periodically report unencrypted information about our node to a map via MQTT + */ + bool map_reporting_enabled = 10; + + /* + * Settings for reporting information about our node to a map via MQTT + */ + MapReportSettings map_report_settings = 11; + } + + /* + * Settings for reporting unencrypted information about our node to a map via MQTT + */ + message MapReportSettings { + /* + * How often we should report our info to the map (in seconds) + */ + uint32 publish_interval_secs = 1; + + /* + * Bits of precision for the location sent (default of 32 is full precision). + */ + uint32 position_precision = 2; + + /* + * Whether we have opted-in to report our location to the map + */ + bool should_report_location = 3; + } + + /* + * RemoteHardwareModule Config + */ + message RemoteHardwareConfig { + /* + * Whether the Module is enabled + */ + bool enabled = 1; + + /* + * Whether the Module allows consumers to read / write to pins not defined in available_pins + */ + bool allow_undefined_pin_access = 2; + + /* + * Exposes the available pins to the mesh for reading and writing + */ + repeated RemoteHardwarePin available_pins = 3; + } + + /* + * NeighborInfoModule Config + */ + message NeighborInfoConfig { + /* + * Whether the Module is enabled + */ + bool enabled = 1; + + /* + * Interval in seconds of how often we should try to send our + * Neighbor Info (minimum is 14400, i.e., 4 hours) + */ + uint32 update_interval = 2; + + /* + * Whether in addition to sending it to MQTT and the PhoneAPI, our NeighborInfo should be transmitted over LoRa. + * Note that this is not available on a channel with default key and name. + */ + bool transmit_over_lora = 3; + } + + /* + * Detection Sensor Module Config + */ + message DetectionSensorConfig { + enum TriggerType { + // Event is triggered if pin is low + LOGIC_LOW = 0; + // Event is triggered if pin is high + LOGIC_HIGH = 1; + // Event is triggered when pin goes high to low + FALLING_EDGE = 2; + // Event is triggered when pin goes low to high + RISING_EDGE = 3; + // Event is triggered on every pin state change, low is considered to be + // "active" + EITHER_EDGE_ACTIVE_LOW = 4; + // Event is triggered on every pin state change, high is considered to be + // "active" + EITHER_EDGE_ACTIVE_HIGH = 5; + } + /* + * Whether the Module is enabled + */ + bool enabled = 1; + + /* + * Interval in seconds of how often we can send a message to the mesh when a + * trigger event is detected + */ + uint32 minimum_broadcast_secs = 2; + + /* + * Interval in seconds of how often we should send a message to the mesh + * with the current state regardless of trigger events When set to 0, only + * trigger events will be broadcasted Works as a sort of status heartbeat + * for peace of mind + */ + uint32 state_broadcast_secs = 3; + + /* + * Send ASCII bell with alert message + * Useful for triggering ext. notification on bell + */ + bool send_bell = 4; + + /* + * Friendly name used to format message sent to mesh + * Example: A name "Motion" would result in a message "Motion detected" + * Maximum length of 20 characters + */ + string name = 5; + + /* + * GPIO pin to monitor for state changes + */ + uint32 monitor_pin = 6; + + /* + * The type of trigger event to be used + */ + TriggerType detection_trigger_type = 7; + + /* + * Whether or not use INPUT_PULLUP mode for GPIO pin + * Only applicable if the board uses pull-up resistors on the pin + */ + bool use_pullup = 8; + } + + /* + * Audio Config for codec2 voice + */ + message AudioConfig { + /* + * Baudrate for codec2 voice + */ + enum Audio_Baud { + CODEC2_DEFAULT = 0; + CODEC2_3200 = 1; + CODEC2_2400 = 2; + CODEC2_1600 = 3; + CODEC2_1400 = 4; + CODEC2_1300 = 5; + CODEC2_1200 = 6; + CODEC2_700 = 7; + CODEC2_700B = 8; + } + + /* + * Whether Audio is enabled + */ + bool codec2_enabled = 1; + + /* + * PTT Pin + */ + uint32 ptt_pin = 2; + + /* + * The audio sample rate to use for codec2 + */ + Audio_Baud bitrate = 3; + + /* + * I2S Word Select + */ + uint32 i2s_ws = 4; + + /* + * I2S Data IN + */ + uint32 i2s_sd = 5; + + /* + * I2S Data OUT + */ + uint32 i2s_din = 6; + + /* + * I2S Clock + */ + uint32 i2s_sck = 7; + } + + /* + * Config for the Paxcounter Module + */ + message PaxcounterConfig { + /* + * Enable the Paxcounter Module + */ + bool enabled = 1; + + /* + * Interval in seconds of how often we should try to send our + * metrics to the mesh + */ + + uint32 paxcounter_update_interval = 2; + + /* + * WiFi RSSI threshold. Defaults to -80 + */ + int32 wifi_threshold = 3; + + /* + * BLE RSSI threshold. Defaults to -80 + */ + int32 ble_threshold = 4; + } + + /* + * Serial Config + */ + message SerialConfig { + /* + * TODO: REPLACE + */ + enum Serial_Baud { + BAUD_DEFAULT = 0; + BAUD_110 = 1; + BAUD_300 = 2; + BAUD_600 = 3; + BAUD_1200 = 4; + BAUD_2400 = 5; + BAUD_4800 = 6; + BAUD_9600 = 7; + BAUD_19200 = 8; + BAUD_38400 = 9; + BAUD_57600 = 10; + BAUD_115200 = 11; + BAUD_230400 = 12; + BAUD_460800 = 13; + BAUD_576000 = 14; + BAUD_921600 = 15; + } + + /* + * TODO: REPLACE + */ + enum Serial_Mode { + DEFAULT = 0; + SIMPLE = 1; + PROTO = 2; + TEXTMSG = 3; + NMEA = 4; + // NMEA messages specifically tailored for CalTopo + CALTOPO = 5; + // Ecowitt WS85 weather station + WS85 = 6; + // VE.Direct is a serial protocol used by Victron Energy products + // https://beta.ivc.no/wiki/index.php/Victron_VE_Direct_DIY_Cable + VE_DIRECT = 7; + //Used to configure and view some parameters of MeshSolar. + //https://heltec.org/project/meshsolar/ + MS_CONFIG = 8; + } + + /* + * Preferences for the SerialModule + */ + bool enabled = 1; + + /* + * TODO: REPLACE + */ + bool echo = 2; + + /* + * RX pin (should match Arduino gpio pin number) + */ + uint32 rxd = 3; + + /* + * TX pin (should match Arduino gpio pin number) + */ + uint32 txd = 4; + + /* + * Serial baud rate + */ + Serial_Baud baud = 5; + + /* + * TODO: REPLACE + */ + uint32 timeout = 6; + + /* + * Mode for serial module operation + */ + Serial_Mode mode = 7; + + /* + * Overrides the platform's defacto Serial port instance to use with Serial module config settings + * This is currently only usable in output modes like NMEA / CalTopo and may behave strangely or not work at all in other modes + * Existing logging over the Serial Console will still be present + */ + bool override_console_serial_port = 8; + } + + /* + * External Notifications Config + */ + message ExternalNotificationConfig { + /* + * Enable the ExternalNotificationModule + */ + bool enabled = 1; + + /* + * When using in On/Off mode, keep the output on for this many + * milliseconds. Default 1000ms (1 second). + */ + uint32 output_ms = 2; + + /* + * Define the output pin GPIO setting Defaults to + * EXT_NOTIFY_OUT if set for the board. + * In standalone devices this pin should drive the LED to match the UI. + */ + uint32 output = 3; + + /* + * Optional: Define a secondary output pin for a vibra motor + * This is used in standalone devices to match the UI. + */ + uint32 output_vibra = 8; + + /* + * Optional: Define a tertiary output pin for an active buzzer + * This is used in standalone devices to to match the UI. + */ + uint32 output_buzzer = 9; + + /* + * IF this is true, the 'output' Pin will be pulled active high, false + * means active low. + */ + bool active = 4; + + /* + * True: Alert when a text message arrives (output) + */ + bool alert_message = 5; + + /* + * True: Alert when a text message arrives (output_vibra) + */ + bool alert_message_vibra = 10; + + /* + * True: Alert when a text message arrives (output_buzzer) + */ + bool alert_message_buzzer = 11; + + /* + * True: Alert when the bell character is received (output) + */ + bool alert_bell = 6; + + /* + * True: Alert when the bell character is received (output_vibra) + */ + bool alert_bell_vibra = 12; + + /* + * True: Alert when the bell character is received (output_buzzer) + */ + bool alert_bell_buzzer = 13; + + /* + * use a PWM output instead of a simple on/off output. This will ignore + * the 'output', 'output_ms' and 'active' settings and use the + * device.buzzer_gpio instead. + */ + bool use_pwm = 7; + + /* + * The notification will toggle with 'output_ms' for this time of seconds. + * Default is 0 which means don't repeat at all. 60 would mean blink + * and/or beep for 60 seconds + */ + uint32 nag_timeout = 14; + + /* + * When true, enables devices with native I2S audio output to use the RTTTL over speaker like a buzzer + * T-Watch S3 and T-Deck for example have this capability + */ + bool use_i2s_as_buzzer = 15; + } + + /* + * Store and Forward Module Config + */ + message StoreForwardConfig { + /* + * Enable the Store and Forward Module + */ + bool enabled = 1; + + /* + * TODO: REPLACE + */ + bool heartbeat = 2; + + /* + * TODO: REPLACE + */ + uint32 records = 3; + + /* + * TODO: REPLACE + */ + uint32 history_return_max = 4; + + /* + * TODO: REPLACE + */ + uint32 history_return_window = 5; + + /* + * Set to true to let this node act as a server that stores received messages and resends them upon request. + */ + bool is_server = 6; + } + + /* + * Preferences for the RangeTestModule + */ + message RangeTestConfig { + /* + * Enable the Range Test Module + */ + bool enabled = 1; + + /* + * Send out range test messages from this node + */ + uint32 sender = 2; + + /* + * Bool value indicating that this node should save a RangeTest.csv file. + * ESP32 Only + */ + bool save = 3; + + /* + * Bool indicating that the node should cleanup / destroy it's RangeTest.csv file. + * ESP32 Only + */ + bool clear_on_reboot = 4; + } + + /* + * Configuration for both device and environment metrics + */ + message TelemetryConfig { + /* + * Interval in seconds of how often we should try to send our + * device metrics to the mesh + */ + uint32 device_update_interval = 1; + + /* + * Interval in seconds of how often we should try to send our + * environment measurements to the mesh + */ + + uint32 environment_update_interval = 2; + + /* + * Preferences for the Telemetry Module (Environment) + * Enable/Disable the telemetry measurement module measurement collection + */ + bool environment_measurement_enabled = 3; + + /* + * Enable/Disable the telemetry measurement module on-device display + */ + bool environment_screen_enabled = 4; + + /* + * We'll always read the sensor in Celsius, but sometimes we might want to + * display the results in Fahrenheit as a "user preference". + */ + bool environment_display_fahrenheit = 5; + + /* + * Enable/Disable the air quality metrics + */ + bool air_quality_enabled = 6; + + /* + * Interval in seconds of how often we should try to send our + * air quality metrics to the mesh + */ + uint32 air_quality_interval = 7; + + /* + * Enable/disable Power metrics + */ + bool power_measurement_enabled = 8; + + /* + * Interval in seconds of how often we should try to send our + * power metrics to the mesh + */ + uint32 power_update_interval = 9; + + /* + * Enable/Disable the power measurement module on-device display + */ + bool power_screen_enabled = 10; + + /* + * Preferences for the (Health) Telemetry Module + * Enable/Disable the telemetry measurement module measurement collection + */ + bool health_measurement_enabled = 11; + + /* + * Interval in seconds of how often we should try to send our + * health metrics to the mesh + */ + uint32 health_update_interval = 12; + + /* + * Enable/Disable the health telemetry module on-device display + */ + bool health_screen_enabled = 13; + + /* + * Enable/Disable the device telemetry module to send metrics to the mesh + * Note: We will still send telemtry to the connected phone / client every minute over the API + */ + bool device_telemetry_enabled = 14; + } + + /* + * Canned Messages Module Config + */ + message CannedMessageConfig { + /* + * TODO: REPLACE + */ + enum InputEventChar { + /* + * TODO: REPLACE + */ + NONE = 0; + + /* + * TODO: REPLACE + */ + UP = 17; + + /* + * TODO: REPLACE + */ + DOWN = 18; + + /* + * TODO: REPLACE + */ + LEFT = 19; + + /* + * TODO: REPLACE + */ + RIGHT = 20; + + /* + * '\n' + */ + SELECT = 10; + + /* + * TODO: REPLACE + */ + BACK = 27; + + /* + * TODO: REPLACE + */ + CANCEL = 24; + } + + /* + * Enable the rotary encoder #1. This is a 'dumb' encoder sending pulses on both A and B pins while rotating. + */ + bool rotary1_enabled = 1; + + /* + * GPIO pin for rotary encoder A port. + */ + uint32 inputbroker_pin_a = 2; + + /* + * GPIO pin for rotary encoder B port. + */ + uint32 inputbroker_pin_b = 3; + + /* + * GPIO pin for rotary encoder Press port. + */ + uint32 inputbroker_pin_press = 4; + + /* + * Generate input event on CW of this kind. + */ + InputEventChar inputbroker_event_cw = 5; + + /* + * Generate input event on CCW of this kind. + */ + InputEventChar inputbroker_event_ccw = 6; + + /* + * Generate input event on Press of this kind. + */ + InputEventChar inputbroker_event_press = 7; + + /* + * Enable the Up/Down/Select input device. Can be RAK rotary encoder or 3 buttons. Uses the a/b/press definitions from inputbroker. + */ + bool updown1_enabled = 8; + + /* + * Enable/disable CannedMessageModule. + */ + bool enabled = 9 [deprecated = true]; + + /* + * Input event origin accepted by the canned message module. + * Can be e.g. "rotEnc1", "upDownEnc1", "scanAndSelect", "cardkb", "serialkb", or keyword "_any" + */ + string allow_input_source = 10 [deprecated = true]; + + /* + * CannedMessageModule also sends a bell character with the messages. + * ExternalNotificationModule can benefit from this feature. + */ + bool send_bell = 11; + } + + /* + Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. + Initially created for the RAK14001 RGB LED module. + */ + message AmbientLightingConfig { + /* + * Sets LED to on or off. + */ + bool led_state = 1; + + /* + * Sets the current for the LED output. Default is 10. + */ + uint32 current = 2; + + /* + * Sets the red LED level. Values are 0-255. + */ + uint32 red = 3; + + /* + * Sets the green LED level. Values are 0-255. + */ + uint32 green = 4; + + /* + * Sets the blue LED level. Values are 0-255. + */ + uint32 blue = 5; + } + + /* + * TODO: REPLACE + */ + oneof payload_variant { + /* + * TODO: REPLACE + */ + MQTTConfig mqtt = 1; + + /* + * TODO: REPLACE + */ + SerialConfig serial = 2; + + /* + * TODO: REPLACE + */ + ExternalNotificationConfig external_notification = 3; + + /* + * TODO: REPLACE + */ + StoreForwardConfig store_forward = 4; + + /* + * TODO: REPLACE + */ + RangeTestConfig range_test = 5; + + /* + * TODO: REPLACE + */ + TelemetryConfig telemetry = 6; + + /* + * TODO: REPLACE + */ + CannedMessageConfig canned_message = 7; + + /* + * TODO: REPLACE + */ + AudioConfig audio = 8; + + /* + * TODO: REPLACE + */ + RemoteHardwareConfig remote_hardware = 9; + + /* + * TODO: REPLACE + */ + NeighborInfoConfig neighbor_info = 10; + + /* + * TODO: REPLACE + */ + AmbientLightingConfig ambient_lighting = 11; + + /* + * TODO: REPLACE + */ + DetectionSensorConfig detection_sensor = 12; + + /* + * TODO: REPLACE + */ + PaxcounterConfig paxcounter = 13; + } +} + +/* + * A GPIO pin definition for remote hardware module + */ +message RemoteHardwarePin { + /* + * GPIO Pin number (must match Arduino) + */ + uint32 gpio_pin = 1; + + /* + * Name for the GPIO pin (i.e. Front gate, mailbox, etc) + */ + string name = 2; + + /* + * Type of GPIO access available to consumers on the mesh + */ + RemoteHardwarePinType type = 3; +} + +enum RemoteHardwarePinType { + /* + * Unset/unused + */ + UNKNOWN = 0; + + /* + * GPIO pin can be read (if it is high / low) + */ + DIGITAL_READ = 1; + + /* + * GPIO pin can be written to (high / low) + */ + DIGITAL_WRITE = 2; +} diff --git a/packages/protobufs/meshtastic/mqtt.options b/packages/protobufs/meshtastic/mqtt.options new file mode 100644 index 00000000..591e898e --- /dev/null +++ b/packages/protobufs/meshtastic/mqtt.options @@ -0,0 +1,8 @@ +*ServiceEnvelope.packet type:FT_POINTER +*ServiceEnvelope.channel_id type:FT_POINTER +*ServiceEnvelope.gateway_id type:FT_POINTER + +*MapReport.long_name max_size:40 +*MapReport.short_name max_size:5 +*MapReport.firmware_version max_size:18 +*MapReport.num_online_local_nodes int_size:16 \ No newline at end of file diff --git a/packages/protobufs/meshtastic/mqtt.proto b/packages/protobufs/meshtastic/mqtt.proto new file mode 100644 index 00000000..4edf0c43 --- /dev/null +++ b/packages/protobufs/meshtastic/mqtt.proto @@ -0,0 +1,112 @@ +syntax = "proto3"; + +package meshtastic; + +import "meshtastic/config.proto"; +import "meshtastic/mesh.proto"; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "MQTTProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * This message wraps a MeshPacket with extra metadata about the sender and how it arrived. + */ +message ServiceEnvelope { + /* + * The (probably encrypted) packet + */ + MeshPacket packet = 1; + + /* + * The global channel ID it was sent on + */ + string channel_id = 2; + + /* + * The sending gateway node ID. Can we use this to authenticate/prevent fake + * nodeid impersonation for senders? - i.e. use gateway/mesh id (which is authenticated) + local node id as + * the globally trusted nodenum + */ + string gateway_id = 3; +} + +/* + * Information about a node intended to be reported unencrypted to a map using MQTT. + */ +message MapReport { + /* + * A full name for this user, i.e. "Kevin Hester" + */ + string long_name = 1; + + /* + * A VERY short name, ideally two characters. + * Suitable for a tiny OLED screen + */ + string short_name = 2; + + /* + * Role of the node that applies specific settings for a particular use-case + */ + Config.DeviceConfig.Role role = 3; + + /* + * Hardware model of the node, i.e. T-Beam, Heltec V3, etc... + */ + HardwareModel hw_model = 4; + + /* + * Device firmware version string + */ + string firmware_version = 5; + + /* + * The region code for the radio (US, CN, EU433, etc...) + */ + Config.LoRaConfig.RegionCode region = 6; + + /* + * Modem preset used by the radio (LongFast, MediumSlow, etc...) + */ + Config.LoRaConfig.ModemPreset modem_preset = 7; + + /* + * Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...) + * and it uses the default frequency slot given the region and modem preset. + */ + bool has_default_channel = 8; + + /* + * Latitude: multiply by 1e-7 to get degrees in floating point + */ + sfixed32 latitude_i = 9; + + /* + * Longitude: multiply by 1e-7 to get degrees in floating point + */ + sfixed32 longitude_i = 10; + + /* + * Altitude in meters above MSL + */ + int32 altitude = 11; + + /* + * Indicates the bits of precision for latitude and longitude set by the sending node + */ + uint32 position_precision = 12; + + /* + * Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT) + */ + uint32 num_online_local_nodes = 13; + + /* + * User has opted in to share their location (map report) with the mqtt server + * Controlled by map_report.should_report_location + */ + bool has_opted_report_location = 14; +} diff --git a/packages/protobufs/meshtastic/paxcount.proto b/packages/protobufs/meshtastic/paxcount.proto new file mode 100644 index 00000000..47b26398 --- /dev/null +++ b/packages/protobufs/meshtastic/paxcount.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "PaxcountProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * TODO: REPLACE + */ +message Paxcount { + /* + * seen Wifi devices + */ + uint32 wifi = 1; + + /* + * Seen BLE devices + */ + uint32 ble = 2; + + /* + * Uptime in seconds + */ + uint32 uptime = 3; +} diff --git a/packages/protobufs/meshtastic/portnums.proto b/packages/protobufs/meshtastic/portnums.proto new file mode 100644 index 00000000..e388a6f2 --- /dev/null +++ b/packages/protobufs/meshtastic/portnums.proto @@ -0,0 +1,244 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "Portnums"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a + * unique 'portnum' for their application. + * If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to this + * master table. + * PortNums should be assigned in the following range: + * 0-63 Core Meshtastic use, do not use for third party apps + * 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application + * 256-511 Use one of these portnums for your private applications that you don't want to register publically + * All other values are reserved. + * Note: This was formerly a Type enum named 'typ' with the same id # + * We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. + * This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically. + */ +enum PortNum { + /* + * Deprecated: do not use in new code (formerly called OPAQUE) + * A message sent from a device outside of the mesh, in a form the mesh does not understand + * NOTE: This must be 0, because it is documented in IMeshService.aidl to be so + * ENCODING: binary undefined + */ + UNKNOWN_APP = 0; + + /* + * A simple UTF-8 text message, which even the little micros in the mesh + * can understand and show on their screen eventually in some circumstances + * even signal might send messages in this form (see below) + * ENCODING: UTF-8 Plaintext (?) + */ + TEXT_MESSAGE_APP = 1; + + /* + * Reserved for built-in GPIO/example app. + * See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number + * ENCODING: Protobuf + */ + REMOTE_HARDWARE_APP = 2; + + /* + * The built-in position messaging app. + * Payload is a Position message. + * ENCODING: Protobuf + */ + POSITION_APP = 3; + + /* + * The built-in user info app. + * Payload is a User message. + * ENCODING: Protobuf + */ + NODEINFO_APP = 4; + + /* + * Protocol control packets for mesh protocol use. + * Payload is a Routing message. + * ENCODING: Protobuf + */ + ROUTING_APP = 5; + + /* + * Admin control packets. + * Payload is a AdminMessage message. + * ENCODING: Protobuf + */ + ADMIN_APP = 6; + + /* + * Compressed TEXT_MESSAGE payloads. + * ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression + * NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed + * payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress + * any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. + */ + TEXT_MESSAGE_COMPRESSED_APP = 7; + + /* + * Waypoint payloads. + * Payload is a Waypoint message. + * ENCODING: Protobuf + */ + WAYPOINT_APP = 8; + + /* + * Audio Payloads. + * Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now + * ENCODING: codec2 audio frames + * NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate. + * This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. + */ + AUDIO_APP = 9; + + /* + * Same as Text Message but originating from Detection Sensor Module. + * NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 + */ + DETECTION_SENSOR_APP = 10; + + /* + * Same as Text Message but used for critical alerts. + */ + ALERT_APP = 11; + + /* + * Module/port for handling key verification requests. + */ + KEY_VERIFICATION_APP = 12; + + /* + * Provides a 'ping' service that replies to any packet it receives. + * Also serves as a small example module. + * ENCODING: ASCII Plaintext + */ + REPLY_APP = 32; + + /* + * Used for the python IP tunnel feature + * ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. + */ + IP_TUNNEL_APP = 33; + + /* + * Paxcounter lib included in the firmware + * ENCODING: protobuf + */ + PAXCOUNTER_APP = 34; + + /* + * Provides a hardware serial interface to send and receive from the Meshtastic network. + * Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic + * network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network. + * Maximum packet size of 240 bytes. + * Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp. + * ENCODING: binary undefined + */ + SERIAL_APP = 64; + + /* + * STORE_FORWARD_APP (Work in Progress) + * Maintained by Jm Casler (MC Hamster) : jm@casler.org + * ENCODING: Protobuf + */ + STORE_FORWARD_APP = 65; + + /* + * Optional port for messages for the range test module. + * ENCODING: ASCII Plaintext + * NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 + */ + RANGE_TEST_APP = 66; + + /* + * Provides a format to send and receive telemetry data from the Meshtastic network. + * Maintained by Charles Crossan (crossan007) : crossan007@gmail.com + * ENCODING: Protobuf + */ + TELEMETRY_APP = 67; + + /* + * Experimental tools for estimating node position without a GPS + * Maintained by Github user a-f-G-U-C (a Meshtastic contributor) + * Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS + * ENCODING: arrays of int64 fields + */ + ZPS_APP = 68; + + /* + * Used to let multiple instances of Linux native applications communicate + * as if they did using their LoRa chip. + * Maintained by GitHub user GUVWAF. + * Project files at https://github.com/GUVWAF/Meshtasticator + * ENCODING: Protobuf (?) + */ + SIMULATOR_APP = 69; + + /* + * Provides a traceroute functionality to show the route a packet towards + * a certain destination would take on the mesh. Contains a RouteDiscovery message as payload. + * ENCODING: Protobuf + */ + TRACEROUTE_APP = 70; + + /* + * Aggregates edge info for the network by sending out a list of each node's neighbors + * ENCODING: Protobuf + */ + NEIGHBORINFO_APP = 71; + + /* + * ATAK Plugin + * Portnum for payloads from the official Meshtastic ATAK plugin + */ + ATAK_PLUGIN = 72; + + /* + * Provides unencrypted information about a node for consumption by a map via MQTT + */ + MAP_REPORT_APP = 73; + + /* + * PowerStress based monitoring support (for automated power consumption testing) + */ + POWERSTRESS_APP = 74; + + /* + * Reticulum Network Stack Tunnel App + * ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface + */ + RETICULUM_TUNNEL_APP = 76; + + /* + * App for transporting Cayenne Low Power Payload, popular for LoRaWAN sensor nodes. Offers ability to send + * arbitrary telemetry over meshtastic that is not covered by telemetry.proto + * ENCODING: CayenneLLP + */ + CAYENNE_APP = 77; + + /* + * Private applications should use portnums >= 256. + * To simplify initial development and testing you can use "PRIVATE_APP" + * in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) + */ + PRIVATE_APP = 256; + + /* + * ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder + * ENCODING: libcotshrink + */ + ATAK_FORWARDER = 257; + + /* + * Currently we limit port nums to no higher than this value + */ + MAX = 511; +} diff --git a/packages/protobufs/meshtastic/powermon.proto b/packages/protobufs/meshtastic/powermon.proto new file mode 100644 index 00000000..77206f4c --- /dev/null +++ b/packages/protobufs/meshtastic/powermon.proto @@ -0,0 +1,103 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "PowerMonProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). + * But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) + */ +message PowerMon { + /* Any significant power changing event in meshtastic should be tagged with a powermon state transition. + * If you are making new meshtastic features feel free to add new entries at the end of this definition. + */ + enum State { + None = 0; + + CPU_DeepSleep = 0x01; + CPU_LightSleep = 0x02; + + /* + The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only + occasionally. In cases where that rail has multiple devices on it we usually want to have logging on + the state of that rail as an independent record. + For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen. + + The log messages will be short and complete (see PowerMon.Event in the protobufs for details). + something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states. + (We use a bitmask for states so that if a log message gets lost it won't be fatal) + */ + Vext1_On = 0x04; + + Lora_RXOn = 0x08; + Lora_TXOn = 0x10; + Lora_RXActive = 0x20; + BT_On = 0x40; + LED_On = 0x80; + + Screen_On = 0x100; + Screen_Drawing = 0x200; + Wifi_On = 0x400; + + /* + * GPS is actively trying to find our location + * See GPSPowerState for more details + */ + GPS_Active = 0x800; + } +} + +/* + * PowerStress testing support via the C++ PowerStress module + */ +message PowerStressMessage { + /* + * What operation would we like the UUT to perform. + * note: senders should probably set want_response in their request packets, so that they can know when the state + * machine has started processing their request + */ + enum Opcode { + /* + * Unset/unused + */ + UNSET = 0; + + PRINT_INFO = 1; // Print board version slog and send an ack that we are alive and ready to process commands + FORCE_QUIET = 2; // Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation) + END_QUIET = 3; // Stop powerstress processing - probably by just rebooting the board + + SCREEN_ON = 16; // Turn the screen on + SCREEN_OFF = 17; // Turn the screen off + + CPU_IDLE = 32; // Let the CPU run but we assume mostly idling for num_seconds + CPU_DEEPSLEEP = 33; // Force deep sleep for FIXME seconds + CPU_FULLON = 34; // Spin the CPU as fast as possible for num_seconds + + LED_ON = 48; // Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes) + LED_OFF = 49; // Force the LED off for num_seconds + + LORA_OFF = 64; // Completely turn off the LORA radio for num_seconds + LORA_TX = 65; // Send Lora packets for num_seconds + LORA_RX = 66; // Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel) + + BT_OFF = 80; // Turn off the BT radio for num_seconds + BT_ON = 81; // Turn on the BT radio for num_seconds + + WIFI_OFF = 96; // Turn off the WIFI radio for num_seconds + WIFI_ON = 97; // Turn on the WIFI radio for num_seconds + + GPS_OFF = 112; // Turn off the GPS radio for num_seconds + GPS_ON = 113; // Turn on the GPS radio for num_seconds + } + + /* + * What type of HardwareMessage is this? + */ + Opcode cmd = 1; + + float num_seconds = 2; +} diff --git a/packages/protobufs/meshtastic/remote_hardware.proto b/packages/protobufs/meshtastic/remote_hardware.proto new file mode 100644 index 00000000..ba4a6930 --- /dev/null +++ b/packages/protobufs/meshtastic/remote_hardware.proto @@ -0,0 +1,75 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "RemoteHardware"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * An example app to show off the module system. This message is used for + * REMOTE_HARDWARE_APP PortNums. + * Also provides easy remote access to any GPIO. + * In the future other remote hardware operations can be added based on user interest + * (i.e. serial output, spi/i2c input/output). + * FIXME - currently this feature is turned on by default which is dangerous + * because no security yet (beyond the channel mechanism). + * It should be off by default and then protected based on some TBD mechanism + * (a special channel once multichannel support is included?) + */ +message HardwareMessage { + /* + * TODO: REPLACE + */ + enum Type { + /* + * Unset/unused + */ + UNSET = 0; + + /* + * Set gpio gpios based on gpio_mask/gpio_value + */ + WRITE_GPIOS = 1; + + /* + * We are now interested in watching the gpio_mask gpios. + * If the selected gpios change, please broadcast GPIOS_CHANGED. + * Will implicitly change the gpios requested to be INPUT gpios. + */ + WATCH_GPIOS = 2; + + /* + * The gpios listed in gpio_mask have changed, the new values are listed in gpio_value + */ + GPIOS_CHANGED = 3; + + /* + * Read the gpios specified in gpio_mask, send back a READ_GPIOS_REPLY reply with gpio_value populated + */ + READ_GPIOS = 4; + + /* + * A reply to READ_GPIOS. gpio_mask and gpio_value will be populated + */ + READ_GPIOS_REPLY = 5; + } + + /* + * What type of HardwareMessage is this? + */ + Type type = 1; + + /* + * What gpios are we changing. Not used for all MessageTypes, see MessageType for details + */ + uint64 gpio_mask = 2; + + /* + * For gpios that were listed in gpio_mask as valid, what are the signal levels for those gpios. + * Not used for all MessageTypes, see MessageType for details + */ + uint64 gpio_value = 3; +} diff --git a/packages/protobufs/meshtastic/rtttl.options b/packages/protobufs/meshtastic/rtttl.options new file mode 100644 index 00000000..171e426d --- /dev/null +++ b/packages/protobufs/meshtastic/rtttl.options @@ -0,0 +1 @@ +*RTTTLConfig.ringtone max_size:231 diff --git a/packages/protobufs/meshtastic/rtttl.proto b/packages/protobufs/meshtastic/rtttl.proto new file mode 100644 index 00000000..11c8b925 --- /dev/null +++ b/packages/protobufs/meshtastic/rtttl.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "RTTTLConfigProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Canned message module configuration. + */ +message RTTTLConfig { + /* + * Ringtone for PWM Buzzer in RTTTL Format. + */ + string ringtone = 1; +} diff --git a/packages/protobufs/meshtastic/storeforward.options b/packages/protobufs/meshtastic/storeforward.options new file mode 100644 index 00000000..57a122cf --- /dev/null +++ b/packages/protobufs/meshtastic/storeforward.options @@ -0,0 +1 @@ +*StoreAndForward.text max_size:233 \ No newline at end of file diff --git a/packages/protobufs/meshtastic/storeforward.proto b/packages/protobufs/meshtastic/storeforward.proto new file mode 100644 index 00000000..651eae57 --- /dev/null +++ b/packages/protobufs/meshtastic/storeforward.proto @@ -0,0 +1,218 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "StoreAndForwardProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * TODO: REPLACE + */ +message StoreAndForward { + /* + * 001 - 063 = From Router + * 064 - 127 = From Client + */ + enum RequestResponse { + /* + * Unset/unused + */ + UNSET = 0; + + /* + * Router is an in error state. + */ + ROUTER_ERROR = 1; + + /* + * Router heartbeat + */ + ROUTER_HEARTBEAT = 2; + + /* + * Router has requested the client respond. This can work as a + * "are you there" message. + */ + ROUTER_PING = 3; + + /* + * The response to a "Ping" + */ + ROUTER_PONG = 4; + + /* + * Router is currently busy. Please try again later. + */ + ROUTER_BUSY = 5; + + /* + * Router is responding to a request for history. + */ + ROUTER_HISTORY = 6; + + /* + * Router is responding to a request for stats. + */ + ROUTER_STATS = 7; + + /* + * Router sends a text message from its history that was a direct message. + */ + ROUTER_TEXT_DIRECT = 8; + + /* + * Router sends a text message from its history that was a broadcast. + */ + ROUTER_TEXT_BROADCAST = 9; + + /* + * Client is an in error state. + */ + CLIENT_ERROR = 64; + + /* + * Client has requested a replay from the router. + */ + CLIENT_HISTORY = 65; + + /* + * Client has requested stats from the router. + */ + CLIENT_STATS = 66; + + /* + * Client has requested the router respond. This can work as a + * "are you there" message. + */ + CLIENT_PING = 67; + + /* + * The response to a "Ping" + */ + CLIENT_PONG = 68; + + /* + * Client has requested that the router abort processing the client's request + */ + CLIENT_ABORT = 106; + } + + /* + * TODO: REPLACE + */ + message Statistics { + /* + * Number of messages we have ever seen + */ + uint32 messages_total = 1; + + /* + * Number of messages we have currently saved our history. + */ + uint32 messages_saved = 2; + + /* + * Maximum number of messages we will save + */ + uint32 messages_max = 3; + + /* + * Router uptime in seconds + */ + uint32 up_time = 4; + + /* + * Number of times any client sent a request to the S&F. + */ + uint32 requests = 5; + + /* + * Number of times the history was requested. + */ + uint32 requests_history = 6; + + /* + * Is the heartbeat enabled on the server? + */ + bool heartbeat = 7; + + /* + * Maximum number of messages the server will return. + */ + uint32 return_max = 8; + + /* + * Maximum history window in minutes the server will return messages from. + */ + uint32 return_window = 9; + } + + /* + * TODO: REPLACE + */ + message History { + /* + * Number of that will be sent to the client + */ + uint32 history_messages = 1; + + /* + * The window of messages that was used to filter the history client requested + */ + uint32 window = 2; + + /* + * Index in the packet history of the last message sent in a previous request to the server. + * Will be sent to the client before sending the history and can be set in a subsequent request to avoid getting packets the server already sent to the client. + */ + uint32 last_request = 3; + } + + /* + * TODO: REPLACE + */ + message Heartbeat { + /* + * Period in seconds that the heartbeat is sent out that will be sent to the client + */ + uint32 period = 1; + + /* + * If set, this is not the primary Store & Forward router on the mesh + */ + uint32 secondary = 2; + } + + /* + * TODO: REPLACE + */ + RequestResponse rr = 1; + + /* + * TODO: REPLACE + */ + oneof variant { + /* + * TODO: REPLACE + */ + Statistics stats = 2; + + /* + * TODO: REPLACE + */ + History history = 3; + + /* + * TODO: REPLACE + */ + Heartbeat heartbeat = 4; + + /* + * Text from history message. + */ + bytes text = 5; + } +} diff --git a/packages/protobufs/meshtastic/telemetry.options b/packages/protobufs/meshtastic/telemetry.options new file mode 100644 index 00000000..81d2aa82 --- /dev/null +++ b/packages/protobufs/meshtastic/telemetry.options @@ -0,0 +1,18 @@ +# options for nanopb +# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options + +*EnvironmentMetrics.iaq int_size:16 +*EnvironmentMetrics.wind_direction int_size:16 +*EnvironmentMetrics.soil_moisture int_size:8 + +*LocalStats.num_online_nodes int_size:16 +*LocalStats.num_total_nodes int_size:16 +*LocalStats.num_tx_dropped int_size:16 + +*HealthMetrics.heart_bpm int_size:8 +*HealthMetrics.spO2 int_size:8 + +*HostMetrics.load1 int_size:16 +*HostMetrics.load5 int_size:16 +*HostMetrics.load15 int_size:16 +*HostMetrics.user_string max_size:200 diff --git a/packages/protobufs/meshtastic/telemetry.proto b/packages/protobufs/meshtastic/telemetry.proto new file mode 100644 index 00000000..448adf32 --- /dev/null +++ b/packages/protobufs/meshtastic/telemetry.proto @@ -0,0 +1,808 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "TelemetryProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +/* + * Key native device metrics such as battery level + */ +message DeviceMetrics { + /* + * 0-100 (>100 means powered) + */ + optional uint32 battery_level = 1; + + /* + * Voltage measured + */ + optional float voltage = 2; + + /* + * Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). + */ + optional float channel_utilization = 3; + + /* + * Percent of airtime for transmission used within the last hour. + */ + optional float air_util_tx = 4; + + /* + * How long the device has been running since the last reboot (in seconds) + */ + optional uint32 uptime_seconds = 5; +} + +/* + * Weather station or other environmental metrics + */ +message EnvironmentMetrics { + /* + * Temperature measured + */ + optional float temperature = 1; + + /* + * Relative humidity percent measured + */ + optional float relative_humidity = 2; + + /* + * Barometric pressure in hPA measured + */ + optional float barometric_pressure = 3; + + /* + * Gas resistance in MOhm measured + */ + optional float gas_resistance = 4; + + /* + * Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) + */ + optional float voltage = 5; + + /* + * Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) + */ + optional float current = 6; + + /* + * relative scale IAQ value as measured by Bosch BME680 . value 0-500. + * Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. + */ + optional uint32 iaq = 7; + + /* + * RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. + */ + optional float distance = 8; + + /* + * VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. + */ + optional float lux = 9; + + /* + * VEML7700 high accuracy white light(irradiance) not calibrated digital 16-bit resolution sensor. + */ + optional float white_lux = 10; + + /* + * Infrared lux + */ + optional float ir_lux = 11; + + /* + * Ultraviolet lux + */ + optional float uv_lux = 12; + + /* + * Wind direction in degrees + * 0 degrees = North, 90 = East, etc... + */ + optional uint32 wind_direction = 13; + + /* + * Wind speed in m/s + */ + optional float wind_speed = 14; + + /* + * Weight in KG + */ + optional float weight = 15; + + /* + * Wind gust in m/s + */ + optional float wind_gust = 16; + + /* + * Wind lull in m/s + */ + optional float wind_lull = 17; + + /* + * Radiation in µR/h + */ + optional float radiation = 18; + + /* + * Rainfall in the last hour in mm + */ + optional float rainfall_1h = 19; + + /* + * Rainfall in the last 24 hours in mm + */ + optional float rainfall_24h = 20; + + /* + * Soil moisture measured (% 1-100) + */ + optional uint32 soil_moisture = 21; + + /* + * Soil temperature measured (*C) + */ + optional float soil_temperature = 22; +} + +/* + * Power Metrics (voltage / current / etc) + */ +message PowerMetrics { + /* + * Voltage (Ch1) + */ + optional float ch1_voltage = 1; + + /* + * Current (Ch1) + */ + optional float ch1_current = 2; + + /* + * Voltage (Ch2) + */ + optional float ch2_voltage = 3; + + /* + * Current (Ch2) + */ + optional float ch2_current = 4; + + /* + * Voltage (Ch3) + */ + optional float ch3_voltage = 5; + + /* + * Current (Ch3) + */ + optional float ch3_current = 6; + + /* + * Voltage (Ch4) + */ + optional float ch4_voltage = 7; + + /* + * Current (Ch4) + */ + optional float ch4_current = 8; + + /* + * Voltage (Ch5) + */ + optional float ch5_voltage = 9; + + /* + * Current (Ch5) + */ + optional float ch5_current = 10; + + /* + * Voltage (Ch6) + */ + optional float ch6_voltage = 11; + + /* + * Current (Ch6) + */ + optional float ch6_current = 12; + + /* + * Voltage (Ch7) + */ + optional float ch7_voltage = 13; + + /* + * Current (Ch7) + */ + optional float ch7_current = 14; + + /* + * Voltage (Ch8) + */ + optional float ch8_voltage = 15; + + /* + * Current (Ch8) + */ + optional float ch8_current = 16; +} + +/* + * Air quality metrics + */ +message AirQualityMetrics { + /* + * Concentration Units Standard PM1.0 in ug/m3 + */ + optional uint32 pm10_standard = 1; + + /* + * Concentration Units Standard PM2.5 in ug/m3 + */ + optional uint32 pm25_standard = 2; + + /* + * Concentration Units Standard PM10.0 in ug/m3 + */ + optional uint32 pm100_standard = 3; + + /* + * Concentration Units Environmental PM1.0 in ug/m3 + */ + optional uint32 pm10_environmental = 4; + + /* + * Concentration Units Environmental PM2.5 in ug/m3 + */ + optional uint32 pm25_environmental = 5; + + /* + * Concentration Units Environmental PM10.0 in ug/m3 + */ + optional uint32 pm100_environmental = 6; + + /* + * 0.3um Particle Count in #/0.1l + */ + optional uint32 particles_03um = 7; + + /* + * 0.5um Particle Count in #/0.1l + */ + optional uint32 particles_05um = 8; + + /* + * 1.0um Particle Count in #/0.1l + */ + optional uint32 particles_10um = 9; + + /* + * 2.5um Particle Count in #/0.1l + */ + optional uint32 particles_25um = 10; + + /* + * 5.0um Particle Count in #/0.1l + */ + optional uint32 particles_50um = 11; + + /* + * 10.0um Particle Count in #/0.1l + */ + optional uint32 particles_100um = 12; + + /* + * CO2 concentration in ppm + */ + optional uint32 co2 = 13; + + /* + * CO2 sensor temperature in degC + */ + optional float co2_temperature = 14; + + /* + * CO2 sensor relative humidity in % + */ + optional float co2_humidity = 15; + + /* + * Formaldehyde sensor formaldehyde concentration in ppb + */ + optional float form_formaldehyde = 16; + + /* + * Formaldehyde sensor relative humidity in %RH + */ + optional float form_humidity = 17; + + /* + * Formaldehyde sensor temperature in degrees Celsius + */ + optional float form_temperature = 18; + + /* + * Concentration Units Standard PM4.0 in ug/m3 + */ + optional uint32 pm40_standard = 19; + + /* + * 4.0um Particle Count in #/0.1l + */ + optional uint32 particles_40um = 20; + + /* + * PM Sensor Temperature + */ + optional float pm_temperature = 21; + + /* + * PM Sensor humidity + */ + optional float pm_humidity = 22; + + /* + * PM Sensor VOC Index + */ + optional float pm_voc_idx = 23; + + /* + * PM Sensor NOx Index + */ + optional float pm_nox_idx = 24; + + /* + * Typical Particle Size in um + */ + optional float particles_tps = 25; +} + +/* + * Local device mesh statistics + */ +message LocalStats { + /* + * How long the device has been running since the last reboot (in seconds) + */ + uint32 uptime_seconds = 1; + /* + * Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). + */ + float channel_utilization = 2; + /* + * Percent of airtime for transmission used within the last hour. + */ + float air_util_tx = 3; + + /* + * Number of packets sent + */ + uint32 num_packets_tx = 4; + + /* + * Number of packets received (both good and bad) + */ + uint32 num_packets_rx = 5; + + /* + * Number of packets received that are malformed or violate the protocol + */ + uint32 num_packets_rx_bad = 6; + + /* + * Number of nodes online (in the past 2 hours) + */ + uint32 num_online_nodes = 7; + + /* + * Number of nodes total + */ + uint32 num_total_nodes = 8; + + /* + * Number of received packets that were duplicates (due to multiple nodes relaying). + * If this number is high, there are nodes in the mesh relaying packets when it's unnecessary, for example due to the ROUTER/REPEATER role. + */ + uint32 num_rx_dupe = 9; + + /* + * Number of packets we transmitted that were a relay for others (not originating from ourselves). + */ + uint32 num_tx_relay = 10; + + /* + * Number of times we canceled a packet to be relayed, because someone else did it before us. + * This will always be zero for ROUTERs/REPEATERs. If this number is high, some other node(s) is/are relaying faster than you. + */ + uint32 num_tx_relay_canceled = 11; + + /* + * Number of bytes used in the heap + */ + uint32 heap_total_bytes = 12; + + /* + * Number of bytes free in the heap + */ + uint32 heap_free_bytes = 13; + + /* + * Number of packets that were dropped because the transmit queue was full. + */ + uint32 num_tx_dropped = 14; +} + +/* + * Health telemetry metrics + */ +message HealthMetrics { + /* + * Heart rate (beats per minute) + */ + optional uint32 heart_bpm = 1; + + /* + * SpO2 (blood oxygen saturation) level + */ + optional uint32 spO2 = 2; + + /* + * Body temperature in degrees Celsius + */ + optional float temperature = 3; +} + +/* + * Linux host metrics + */ +message HostMetrics { + /* + * Host system uptime + */ + uint32 uptime_seconds = 1; + + /* + * Host system free memory + */ + uint64 freemem_bytes = 2; + + /* + * Host system disk space free for / + */ + uint64 diskfree1_bytes = 3; + + /* + * Secondary system disk space free + */ + optional uint64 diskfree2_bytes = 4; + + /* + * Tertiary disk space free + */ + optional uint64 diskfree3_bytes = 5; + + /* + * Host system one minute load in 1/100ths + */ + uint32 load1 = 6; + + /* + * Host system five minute load in 1/100ths + */ + uint32 load5 = 7; + + /* + * Host system fifteen minute load in 1/100ths + */ + uint32 load15 = 8; + + /* + * Optional User-provided string for arbitrary host system information + * that doesn't make sense as a dedicated entry. + */ + optional string user_string = 9; +} + +/* + * Types of Measurements the telemetry module is equipped to handle + */ +message Telemetry { + /* + * Seconds since 1970 - or 0 for unknown/unset + */ + fixed32 time = 1; + + oneof variant { + /* + * Key native device metrics such as battery level + */ + DeviceMetrics device_metrics = 2; + + /* + * Weather station or other environmental metrics + */ + EnvironmentMetrics environment_metrics = 3; + + /* + * Air quality metrics + */ + AirQualityMetrics air_quality_metrics = 4; + + /* + * Power Metrics + */ + PowerMetrics power_metrics = 5; + + /* + * Local device mesh statistics + */ + LocalStats local_stats = 6; + + /* + * Health telemetry metrics + */ + HealthMetrics health_metrics = 7; + + /* + * Linux host metrics + */ + HostMetrics host_metrics = 8; + } +} + +/* + * Supported I2C Sensors for telemetry in Meshtastic + */ +enum TelemetrySensorType { + /* + * No external telemetry sensor explicitly set + */ + SENSOR_UNSET = 0; + + /* + * High accuracy temperature, pressure, humidity + */ + BME280 = 1; + + /* + * High accuracy temperature, pressure, humidity, and air resistance + */ + BME680 = 2; + + /* + * Very high accuracy temperature + */ + MCP9808 = 3; + + /* + * Moderate accuracy current and voltage + */ + INA260 = 4; + + /* + * Moderate accuracy current and voltage + */ + INA219 = 5; + + /* + * High accuracy temperature and pressure + */ + BMP280 = 6; + + /* + * High accuracy temperature and humidity + */ + SHTC3 = 7; + + /* + * High accuracy pressure + */ + LPS22 = 8; + + /* + * 3-Axis magnetic sensor + */ + QMC6310 = 9; + + /* + * 6-Axis inertial measurement sensor + */ + QMI8658 = 10; + + /* + * 3-Axis magnetic sensor + */ + QMC5883L = 11; + + /* + * High accuracy temperature and humidity + */ + SHT31 = 12; + + /* + * PM2.5 air quality sensor + */ + PMSA003I = 13; + + /* + * INA3221 3 Channel Voltage / Current Sensor + */ + INA3221 = 14; + + /* + * BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280) + */ + BMP085 = 15; + + /* + * RCWL-9620 Doppler Radar Distance Sensor, used for water level detection + */ + RCWL9620 = 16; + + /* + * Sensirion High accuracy temperature and humidity + */ + SHT4X = 17; + + /* + * VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. + */ + VEML7700 = 18; + + /* + * MLX90632 non-contact IR temperature sensor. + */ + MLX90632 = 19; + + /* + * TI OPT3001 Ambient Light Sensor + */ + OPT3001 = 20; + + /* + * Lite On LTR-390UV-01 UV Light Sensor + */ + LTR390UV = 21; + + /* + * AMS TSL25911FN RGB Light Sensor + */ + TSL25911FN = 22; + + /* + * AHT10 Integrated temperature and humidity sensor + */ + AHT10 = 23; + + /* + * DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) + */ + DFROBOT_LARK = 24; + + /* + * NAU7802 Scale Chip or compatible + */ + NAU7802 = 25; + + /* + * BMP3XX High accuracy temperature and pressure + */ + BMP3XX = 26; + + /* + * ICM-20948 9-Axis digital motion processor + */ + ICM20948 = 27; + + /* + * MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) + */ + MAX17048 = 28; + + /* + * Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor + */ + CUSTOM_SENSOR = 29; + + /* + * MAX30102 Pulse Oximeter and Heart-Rate Sensor + */ + MAX30102 = 30; + + /* + * MLX90614 non-contact IR temperature sensor + */ + MLX90614 = 31; + + /* + * SCD40/SCD41 CO2, humidity, temperature sensor + */ + SCD4X = 32; + + /* + * ClimateGuard RadSens, radiation, Geiger-Muller Tube + */ + RADSENS = 33; + + /* + * High accuracy current and voltage + */ + INA226 = 34; + + /* + * DFRobot Gravity tipping bucket rain gauge + */ + DFROBOT_RAIN = 35; + + /* + * Infineon DPS310 High accuracy pressure and temperature + */ + DPS310 = 36; + + /* + * RAKWireless RAK12035 Soil Moisture Sensor Module + */ + RAK12035 = 37; + + /* + * MAX17261 lipo battery gauge + */ + MAX17261 = 38; + + /* + * PCT2075 Temperature Sensor + */ + PCT2075 = 39; + + /* + * ADS1X15 ADC + */ + ADS1X15 = 40; + + /* + * ADS1X15 ADC_ALT + */ + ADS1X15_ALT = 41; + + /* + * Sensirion SFA30 Formaldehyde sensor + */ + SFA30 = 42; + + /* + * SEN5X PM SENSORS + */ + SEN5X = 43; + /* + * TSL2561 light sensor + */ + TSL2561 = 44; +} + +/* + * NAU7802 Telemetry configuration, for saving to flash + */ +message Nau7802Config { + /* + * The offset setting for the NAU7802 + */ + int32 zeroOffset = 1; + + /* + * The calibration factor for the NAU7802 + */ + float calibrationFactor = 2; +} diff --git a/packages/protobufs/meshtastic/xmodem.options b/packages/protobufs/meshtastic/xmodem.options new file mode 100644 index 00000000..3af6125a --- /dev/null +++ b/packages/protobufs/meshtastic/xmodem.options @@ -0,0 +1,6 @@ +# options for nanopb +# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options + +*XModem.buffer max_size:128 +*XModem.seq int_size:16 +*XModem.crc16 int_size:16 diff --git a/packages/protobufs/meshtastic/xmodem.proto b/packages/protobufs/meshtastic/xmodem.proto new file mode 100644 index 00000000..732780a3 --- /dev/null +++ b/packages/protobufs/meshtastic/xmodem.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package meshtastic; + +option csharp_namespace = "Meshtastic.Protobufs"; +option go_package = "github.com/meshtastic/go/generated"; +option java_outer_classname = "XmodemProtos"; +option java_package = "com.geeksville.mesh"; +option swift_prefix = ""; + +message XModem { + enum Control { + NUL = 0; + SOH = 1; + STX = 2; + EOT = 4; + ACK = 6; + NAK = 21; + CAN = 24; + CTRLZ = 26; + } + + Control control = 1; + uint32 seq = 2; + uint32 crc16 = 3; + bytes buffer = 4; +} diff --git a/packages/protobufs/nanopb.proto b/packages/protobufs/nanopb.proto new file mode 100644 index 00000000..1c107c16 --- /dev/null +++ b/packages/protobufs/nanopb.proto @@ -0,0 +1,185 @@ +// Custom options for defining: +// - Maximum size of string/bytes +// - Maximum number of elements in array +// +// These are used by nanopb to generate statically allocable structures +// for memory-limited environments. + +syntax = "proto2"; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/meshtastic/go/generated"; +option java_package = "fi.kapsi.koti.jpa.nanopb"; + +enum FieldType { + FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible. + FT_CALLBACK = 1; // Always generate a callback field. + FT_POINTER = 4; // Always generate a dynamically allocated field. + FT_STATIC = 2; // Generate a static field or raise an exception if not possible. + FT_IGNORE = 3; // Ignore the field completely. + FT_INLINE = 5; // Legacy option, use the separate 'fixed_length' option instead +} + +enum IntSize { + IS_DEFAULT = 0; // Default, 32/64bit based on type in .proto + IS_8 = 8; + IS_16 = 16; + IS_32 = 32; + IS_64 = 64; +} + +enum TypenameMangling { + M_NONE = 0; // Default, no typename mangling + M_STRIP_PACKAGE = 1; // Strip current package name + M_FLATTEN = 2; // Only use last path component + M_PACKAGE_INITIALS = 3; // Replace the package name by the initials +} + +enum DescriptorSize { + DS_AUTO = 0; // Select minimal size based on field type + DS_1 = 1; // 1 word; up to 15 byte fields, no arrays + DS_2 = 2; // 2 words; up to 4095 byte fields, 4095 entry arrays + DS_4 = 4; // 4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays + DS_8 = 8; // 8 words; up to 2^32-1 entry arrays +} + +// This is the inner options message, which basically defines options for +// a field. When it is used in message or file scope, it applies to all +// fields. +message NanoPBOptions { + // Allocated size for 'bytes' and 'string' fields. + // For string fields, this should include the space for null terminator. + optional int32 max_size = 1; + + // Maximum length for 'string' fields. Setting this is equivalent + // to setting max_size to a value of length+1. + optional int32 max_length = 14; + + // Allocated number of entries in arrays ('repeated' fields) + optional int32 max_count = 2; + + // Size of integer fields. Can save some memory if you don't need + // full 32 bits for the value. + optional IntSize int_size = 7 [default = IS_DEFAULT]; + + // Force type of field (callback or static allocation) + optional FieldType type = 3 [default = FT_DEFAULT]; + + // Use long names for enums, i.e. EnumName_EnumValue. + optional bool long_names = 4 [default = true]; + + // Add 'packed' attribute to generated structs. + // Note: this cannot be used on CPUs that break on unaligned + // accesses to variables. + optional bool packed_struct = 5 [default = false]; + + // Add 'packed' attribute to generated enums. + optional bool packed_enum = 10 [default = false]; + + // Skip this message + optional bool skip_message = 6 [default = false]; + + // Generate oneof fields as normal optional fields instead of union. + optional bool no_unions = 8 [default = false]; + + // integer type tag for a message + optional uint32 msgid = 9; + + // decode oneof as anonymous union + optional bool anonymous_oneof = 11 [default = false]; + + // Proto3 singular field does not generate a "has_" flag + optional bool proto3 = 12 [default = false]; + + // Force proto3 messages to have no "has_" flag. + // This was default behavior until nanopb-0.4.0. + optional bool proto3_singular_msgs = 21 [default = false]; + + // Generate an enum->string mapping function (can take up lots of space). + optional bool enum_to_string = 13 [default = false]; + + // Generate bytes arrays with fixed length + optional bool fixed_length = 15 [default = false]; + + // Generate repeated field with fixed count + optional bool fixed_count = 16 [default = false]; + + // Generate message-level callback that is called before decoding submessages. + // This can be used to set callback fields for submsgs inside oneofs. + optional bool submsg_callback = 22 [default = false]; + + // Shorten or remove package names from type names. + // This option applies only on the file level. + optional TypenameMangling mangle_names = 17 [default = M_NONE]; + + // Data type for storage associated with callback fields. + optional string callback_datatype = 18 [default = "pb_callback_t"]; + + // Callback function used for encoding and decoding. + // Prior to nanopb-0.4.0, the callback was specified in per-field pb_callback_t + // structure. This is still supported, but does not work inside e.g. oneof or pointer + // fields. Instead, a new method allows specifying a per-message callback that + // will be called for all callback fields in a message type. + optional string callback_function = 19 [default = "pb_default_field_callback"]; + + // Select the size of field descriptors. This option has to be defined + // for the whole message, not per-field. Usually automatic selection is + // ok, but if it results in compilation errors you can increase the field + // size here. + optional DescriptorSize descriptorsize = 20 [default = DS_AUTO]; + + // Set default value for has_ fields. + optional bool default_has = 23 [default = false]; + + // Extra files to include in generated `.pb.h` + repeated string include = 24; + + // Automatic includes to exclude from generated `.pb.h` + // Same as nanopb_generator.py command line flag -x. + repeated string exclude = 26; + + // Package name that applies only for nanopb. + optional string package = 25; + + // Override type of the field in generated C code. Only to be used with related field types + optional google.protobuf.FieldDescriptorProto.Type type_override = 27; + + // Due to historical reasons, nanopb orders fields in structs by their tag number + // instead of the order in .proto. Set this to false to keep the .proto order. + // The default value will probably change to false in nanopb-0.5.0. + optional bool sort_by_tag = 28 [default = true]; + + // Set the FT_DEFAULT field conversion strategy. + // A field that can become a static member of a c struct (e.g. int, bool, etc) + // will be a a static field. + // Fields with dynamic length are converted to either a pointer or a callback. + optional FieldType fallback_type = 29 [default = FT_CALLBACK]; +} + +// Extensions to protoc 'Descriptor' type in order to define options +// inside a .proto file. +// +// Protocol Buffers extension number registry +// -------------------------------- +// Project: Nanopb +// Contact: Petteri Aimonen +// Web site: http://kapsi.fi/~jpa/nanopb +// Extensions: 1010 (all types) +// -------------------------------- + +extend google.protobuf.FileOptions { + optional NanoPBOptions nanopb_fileopt = 1010; +} + +extend google.protobuf.MessageOptions { + optional NanoPBOptions nanopb_msgopt = 1010; +} + +extend google.protobuf.EnumOptions { + optional NanoPBOptions nanopb_enumopt = 1010; +} + +extend google.protobuf.FieldOptions { + optional NanoPBOptions nanopb = 1010; +} diff --git a/packages/protobufs/package.json b/packages/protobufs/package.json new file mode 100644 index 00000000..ee31ed5e --- /dev/null +++ b/packages/protobufs/package.json @@ -0,0 +1,30 @@ +{ + "name": "@meshtastic/protobufs-ws", + "private": true, + "version": "0.0.0", + "type": "module", + "description": "Workspace package for Meshtastic protobuf stubs (local dev only). This package is published to the JSR registry separately.", + "license": "GPL-3.0-only", + "files": [ + "./packages/ts/dist/" + ], + "exports": { + ".": { + "types": "./packages/ts/dist/mod.d.ts", + "default": "./packages/ts/dist/mod.js" + }, + "./*": "./packages/ts/dist/*" + }, + "types": "./packages/ts/dist/mod.d.ts", + "sideEffects": false, + "scripts": { + "gen": "buf generate", + "clean": "rimraf dist", + "build": "pnpm run clean && pnpm run gen" + }, + "dependencies": {}, + "devDependencies": { + "@bufbuild/protoc-gen-es": "^1.9.0", + "rimraf": "^6.0.0" + } +} diff --git a/packages/protobufs/packages/ts/README.md b/packages/protobufs/packages/ts/README.md new file mode 100644 index 00000000..9e361977 --- /dev/null +++ b/packages/protobufs/packages/ts/README.md @@ -0,0 +1,16 @@ +# 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) +[![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) + +## Overview + +The [Protobuf](https://developers.google.com/protocol-buffers) message definitions for the Meshtastic project (used by apps and the device firmware). + +**[Documentation/API Reference](https://buf.build/meshtastic/protobufs)** + +## Stats + +![Alt](https://repobeats.axiom.co/api/embed/47e9ee1d81d9c0fdd2b4b5b4c673adb1756f6db5.svg "Repobeats analytics image") diff --git a/packages/protobufs/packages/ts/deno.json b/packages/protobufs/packages/ts/deno.json new file mode 100644 index 00000000..b5f91df0 --- /dev/null +++ b/packages/protobufs/packages/ts/deno.json @@ -0,0 +1,13 @@ +{ + "name": "@meshtastic/protobufs", + "version": "__PACKAGE_VERSION__", + "exports": { + ".": "./mod.ts" + }, + "imports": { + "@bufbuild/protobuf": "npm:@bufbuild/protobuf@^2.9.0" + }, + "publish": { + "exclude": ["!dist"] + } +} diff --git a/packages/protobufs/packages/ts/deno.lock b/packages/protobufs/packages/ts/deno.lock new file mode 100644 index 00000000..4f69667e --- /dev/null +++ b/packages/protobufs/packages/ts/deno.lock @@ -0,0 +1,384 @@ +{ + "version": "5", + "specifiers": { + "npm:@bufbuild/protobuf@^2.9.0": "2.9.0", + "npm:tsdown@~0.15.6": "0.15.6_typescript@5.9.3_rolldown@1.0.0-beta.42", + "npm:typescript@^5.9.3": "5.9.3" + }, + "npm": { + "@babel/generator@7.28.3": { + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dependencies": [ + "@babel/parser", + "@babel/types", + "@jridgewell/gen-mapping", + "@jridgewell/trace-mapping", + "jsesc" + ] + }, + "@babel/helper-string-parser@7.27.1": { + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier@7.27.1": { + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" + }, + "@babel/parser@7.28.4": { + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dependencies": [ + "@babel/types" + ], + "bin": true + }, + "@babel/types@7.28.4": { + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dependencies": [ + "@babel/helper-string-parser", + "@babel/helper-validator-identifier" + ] + }, + "@bufbuild/protobuf@2.9.0": { + "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==" + }, + "@emnapi/core@1.5.0": { + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dependencies": [ + "@emnapi/wasi-threads", + "tslib" + ] + }, + "@emnapi/runtime@1.5.0": { + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dependencies": [ + "tslib" + ] + }, + "@emnapi/wasi-threads@1.1.0": { + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "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.0.7": { + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "dependencies": [ + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util" + ] + }, + "@oxc-project/types@0.94.0": { + "integrity": "sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==" + }, + "@quansync/fs@0.1.5": { + "integrity": "sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==", + "dependencies": [ + "quansync" + ] + }, + "@rolldown/binding-android-arm64@1.0.0-beta.42": { + "integrity": "sha512-W5ZKF3TP3bOWuBfotAGp+UGjxOkGV7jRmIRbBA7NFjggx7Oi6vOmGDqpHEIX7kDCiry1cnIsWQaxNvWbMdkvzQ==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@rolldown/binding-darwin-arm64@1.0.0-beta.42": { + "integrity": "sha512-abw/wtgJA8OCgaTlL+xJxnN/Z01BwV1rfzIp5Hh9x+IIO6xOBfPsQ0nzi0+rWx3TyZ9FZXyC7bbC+5NpQ9EaXQ==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@rolldown/binding-darwin-x64@1.0.0-beta.42": { + "integrity": "sha512-Y/UrZIRVr8CvXVEB88t6PeC46r1K9/QdPEo2ASE/b/KBEyXIx+QbM6kv9QfQVWU2Atly2+SVsQzxQsIvuk3lZQ==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@rolldown/binding-freebsd-x64@1.0.0-beta.42": { + "integrity": "sha512-zRM0oOk7BZiy6DoWBvdV4hyEg+j6+WcBZIMHVirMEZRu8hd18kZdJkg+bjVMfCEhwpWeFUfBfZ1qcaZ5UdYzlQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.42": { + "integrity": "sha512-6RjFaC52QNwo7ilU8C5H7swbGlgfTkG9pudXwzr3VYyT18s0C9gLg3mvc7OMPIGqNxnQ0M5lU8j6aQCk2DTRVg==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@rolldown/binding-linux-arm64-gnu@1.0.0-beta.42": { + "integrity": "sha512-LMYHM5Sf6ROq+VUwHMDVX2IAuEsWTv4SnlFEedBnMGpvRuQ14lCmD4m5Q8sjyAQCgyha9oghdGoK8AEg1sXZKg==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rolldown/binding-linux-arm64-musl@1.0.0-beta.42": { + "integrity": "sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@rolldown/binding-linux-x64-gnu@1.0.0-beta.42": { + "integrity": "sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rolldown/binding-linux-x64-musl@1.0.0-beta.42": { + "integrity": "sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@rolldown/binding-openharmony-arm64@1.0.0-beta.42": { + "integrity": "sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@rolldown/binding-wasm32-wasi@1.0.0-beta.42": { + "integrity": "sha512-2Ft32F7uiDTrGZUKws6CLNTlvTWHC33l4vpXrzUucf9rYtUThAdPCOt89Pmn13tNX6AulxjGEP2R0nZjTSW3eQ==", + "dependencies": [ + "@napi-rs/wasm-runtime" + ], + "cpu": ["wasm32"] + }, + "@rolldown/binding-win32-arm64-msvc@1.0.0-beta.42": { + "integrity": "sha512-hC1kShXW/z221eG+WzQMN06KepvPbMBknF0iGR3VMYJLOe9gwnSTfGxFT5hf8XrPv7CEZqTWRd0GQpkSHRbGsw==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@rolldown/binding-win32-ia32-msvc@1.0.0-beta.42": { + "integrity": "sha512-AICBYromawouGjj+GS33369E8Vwhy6UwhQEhQ5evfS8jPCsyVvoICJatbDGDGH01dwtVGLD5eDFzPicUOVpe4g==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@rolldown/binding-win32-x64-msvc@1.0.0-beta.42": { + "integrity": "sha512-XpZ0M+tjoEiSc9c+uZR7FCnOI0uxDRNs1elGOMjeB0pUP1QmvVbZGYNsyLbLoP4u7e3VQN8rie1OQ8/mB6rcJg==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@rolldown/pluginutils@1.0.0-beta.42": { + "integrity": "sha512-N7pQzk9CyE7q0bBN/q0J8s6Db279r5kUZc6d7/wWRe9/zXqC52HQovVyu6iXPIDY4BEzzgbVLhVFXrOuGJ22ZQ==" + }, + "@tybys/wasm-util@0.10.1": { + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dependencies": [ + "tslib" + ] + }, + "ansis@4.2.0": { + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==" + }, + "ast-kit@2.1.3": { + "integrity": "sha512-TH+b3Lv6pUjy/Nu0m6A2JULtdzLpmqF9x1Dhj00ZoEiML8qvVA9j1flkzTKNYgdEhWrjDwtWNpyyCUbfQe514g==", + "dependencies": [ + "@babel/parser", + "pathe" + ] + }, + "birpc@2.6.1": { + "integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==" + }, + "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.4": { + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" + }, + "diff@8.0.2": { + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==" + }, + "dts-resolver@2.1.2": { + "integrity": "sha512-xeXHBQkn2ISSXxbJWD828PFjtyg+/UrMDo7W4Ffcs7+YWCquxU8YjV1KoxuiL+eJ5pg3ll+bC6flVv61L3LKZg==" + }, + "empathic@2.0.0": { + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==" + }, + "fdir@6.5.0_picomatch@4.0.3": { + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dependencies": [ + "picomatch" + ], + "optionalPeers": [ + "picomatch" + ] + }, + "get-tsconfig@4.12.0": { + "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", + "dependencies": [ + "resolve-pkg-maps" + ] + }, + "hookable@5.5.3": { + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + }, + "jiti@2.6.1": { + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "bin": true + }, + "jsesc@3.1.0": { + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": true + }, + "magic-string@0.30.19": { + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dependencies": [ + "@jridgewell/sourcemap-codec" + ] + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "pathe@2.0.3": { + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, + "picomatch@4.0.3": { + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==" + }, + "quansync@0.2.11": { + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==" + }, + "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.16.11_rolldown@1.0.0-beta.42_typescript@5.9.3": { + "integrity": "sha512-9IQDaPvPqTx3RjG2eQCK5GYZITo203BxKunGI80AGYicu1ySFTUyugicAaTZWRzFWh9DSnzkgNeMNbDWBbSs0w==", + "dependencies": [ + "@babel/generator", + "@babel/parser", + "@babel/types", + "ast-kit", + "birpc", + "debug", + "dts-resolver", + "get-tsconfig", + "magic-string", + "rolldown", + "typescript" + ], + "optionalPeers": [ + "typescript" + ] + }, + "rolldown@1.0.0-beta.42": { + "integrity": "sha512-xaPcckj+BbJhYLsv8gOqezc8EdMcKKe/gk8v47B0KPvgABDrQ0qmNPAiT/gh9n9Foe0bUkEv2qzj42uU5q1WRg==", + "dependencies": [ + "@oxc-project/types", + "@rolldown/pluginutils", + "ansis" + ], + "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-x64-gnu", + "@rolldown/binding-linux-x64-musl", + "@rolldown/binding-openharmony-arm64", + "@rolldown/binding-wasm32-wasi", + "@rolldown/binding-win32-arm64-msvc", + "@rolldown/binding-win32-ia32-msvc", + "@rolldown/binding-win32-x64-msvc" + ], + "bin": true + }, + "semver@7.7.3": { + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "bin": true + }, + "tinyexec@1.0.1": { + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==" + }, + "tinyglobby@0.2.15_picomatch@4.0.3": { + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dependencies": [ + "fdir", + "picomatch" + ] + }, + "tree-kill@1.2.2": { + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": true + }, + "tsdown@0.15.6_typescript@5.9.3_rolldown@1.0.0-beta.42": { + "integrity": "sha512-W6++O3JeV9gm3JY6P/vLiC7zzTcJbZhQxXb+p3AvRMpDOPBIg82yXULyZCcwjsihY/bFG+Qw37HkezZbP7fzUg==", + "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@5.9.3": { + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "bin": true + }, + "unconfig@7.3.3": { + "integrity": "sha512-QCkQoOnJF8L107gxfHL0uavn7WD9b3dpBcFX6HtfQYmjw2YzWxGuFQ0N0J6tE9oguCBJn9KOvfqYDCMPHIZrBA==", + "dependencies": [ + "@quansync/fs", + "defu", + "jiti", + "quansync" + ] + } + }, + "workspace": { + "dependencies": [ + "npm:@bufbuild/protobuf@^2.9.0" + ], + "packageJson": { + "dependencies": [ + "npm:@bufbuild/protobuf@^2.9.0", + "npm:tsdown@~0.15.6", + "npm:typescript@^5.9.3" + ] + } + } +} diff --git a/packages/protobufs/packages/ts/mod.ts b/packages/protobufs/packages/ts/mod.ts new file mode 100644 index 00000000..b043e496 --- /dev/null +++ b/packages/protobufs/packages/ts/mod.ts @@ -0,0 +1,20 @@ +export * as Admin from "./lib/admin_pb.ts"; +export * as AppOnly from "./lib/apponly_pb.ts"; +export * as ATAK from "./lib/atak_pb.ts"; +export * as CannedMessages from "./lib/cannedmessages_pb.ts"; +export * as Channel from "./lib/channel_pb.ts"; +export * as ClientOnly from "./lib/clientonly_pb.ts"; +export * as Config from "./lib/config_pb.ts"; +export * as ConnectionStatus from "./lib/connection_status_pb.ts"; +export * as LocalOnly from "./lib/localonly_pb.ts"; +export * as Mesh from "./lib/mesh_pb.ts"; +export * as ModuleConfig from "./lib/module_config_pb.ts"; +export * as Mqtt from "./lib/mqtt_pb.ts"; +export * as PaxCount from "./lib/paxcount_pb.ts"; +export * as Portnums from "./lib/portnums_pb.ts"; +export * as PowerMon from "./lib/powermon_pb.ts"; +export * as RemoteHardware from "./lib/remote_hardware_pb.ts"; +export * as Rtttl from "./lib/rtttl_pb.ts"; +export * as StoreForward from "./lib/storeforward_pb.ts"; +export * as Telemetry from "./lib/telemetry_pb.ts"; +export * as Xmodem from "./lib/xmodem_pb.ts"; diff --git a/packages/web/src/routes.tsx b/packages/web/src/routes.tsx index e134c4b7..07125f82 100644 --- a/packages/web/src/routes.tsx +++ b/packages/web/src/routes.tsx @@ -74,6 +74,41 @@ const mapRoute = createRoute({ component: MapPage, }); +const coordParamsSchema = z.object({ + // Accept "strings" from the URL, coerce to number, then validate + long: z.coerce + .number() + .refine( + (n) => Number.isFinite(n) && n >= -180 && n <= 180, + "Invalid longitude (-180..180).", + ), + lat: z.coerce + .number() + .refine( + (n) => Number.isFinite(n) && n >= -90 && n <= 90, + "Invalid latitude (-90..90).", + ), + // Typical web map zoom levels ~0..22 (adjust if your map lib differs) + zoom: z.coerce + .number() + .int() + .min(0, "Zoom too small.") + .max(22, "Zoom too large."), +}); + +export const mapWithParamsRoute = createRoute({ + getParentRoute: () => rootRoute, + path: "/map/$long/$lat/$zoom", + component: MapPage, + parseParams: (raw) => coordParamsSchema.parse(raw), + // // This controls how params are serialized when you navigate/link + // stringifyParams: (p) => ({ + // long: String(p.long), + // lat: String(p.lat), + // zoom: String(p.zoom), + // }), +}); + const configRoute = createRoute({ getParentRoute: () => rootRoute, path: "/config", @@ -97,6 +132,7 @@ const routeTree = rootRoute.addChildren([ messagesRoute, messagesWithParamsRoute, mapRoute, + mapWithParamsRoute, configRoute, nodesRoute, dialogWithParamsRoute, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb95c080..f6ed6576 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@bufbuild/protobuf': - specifier: ^2.8.0 - version: 2.8.0 + specifier: ^2.9.0 + version: 2.9.0 '@meshtastic/protobufs': specifier: npm:@jsr/meshtastic__protobufs@^2.7.8 version: '@jsr/meshtastic__protobufs@2.7.8' @@ -43,6 +43,15 @@ importers: specifier: npm:crc@^4.3.2 version: 4.3.2 + packages/protobufs: + devDependencies: + '@bufbuild/protoc-gen-es': + specifier: ^1.9.0 + version: 1.10.1(@bufbuild/protobuf@1.10.1) + rimraf: + specifier: ^6.0.0 + version: 6.0.1 + packages/transport-deno: dependencies: '@meshtastic/core': @@ -924,24 +933,28 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [musl] '@biomejs/cli-linux-arm64@2.2.4': resolution: {integrity: sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-x64-musl@2.2.4': resolution: {integrity: sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [musl] '@biomejs/cli-linux-x64@2.2.4': resolution: {integrity: sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [glibc] '@biomejs/cli-win32-arm64@2.2.4': resolution: {integrity: sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==} @@ -955,8 +968,24 @@ packages: cpu: [x64] os: [win32] - '@bufbuild/protobuf@2.8.0': - resolution: {integrity: sha512-r1/0w5C9dkbcdjyxY8ZHsC5AOWg4Pnzhm2zu7LO4UHSounp2tMm6Y+oioV9zlGbLveE7YaWRDUk48WLxRDgoqg==} + '@bufbuild/protobuf@1.10.1': + resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==} + + '@bufbuild/protobuf@2.9.0': + resolution: {integrity: sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==} + + '@bufbuild/protoc-gen-es@1.10.1': + resolution: {integrity: sha512-YADugbvibIdZSb0NGf5OF87IyKTuMvMFZ7vMHgm6pL1SCfDwJ/ZRianTdrPG9hq/gOipK+NwHmXBViyS3J7nxA==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + '@bufbuild/protobuf': 1.10.1 + peerDependenciesMeta: + '@bufbuild/protobuf': + optional: true + + '@bufbuild/protoplugin@1.10.1': + resolution: {integrity: sha512-LaSbfwabAFIvbVnbn8jWwElRoffCIxhVraO8arliVwWupWezHLXgqPHEYLXZY/SsAR+/YsFBQJa8tAGtNPJyaQ==} '@emnapi/core@1.5.0': resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} @@ -1303,6 +1332,18 @@ packages: peerDependencies: react-hook-form: ^7.55.0 + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1946,24 +1987,28 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.42': resolution: {integrity: sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.42': resolution: {integrity: sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.42': resolution: {integrity: sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.42': resolution: {integrity: sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==} @@ -2117,111 +2162,133 @@ packages: resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.50.1': resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.46.2': resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.50.1': resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.46.2': resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.50.1': resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.46.2': resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-musl@4.50.1': resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.46.2': resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loongarch64-gnu@4.50.1': resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.46.2': resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.50.1': resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.46.2': resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.50.1': resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.46.2': resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.50.1': resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.46.2': resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.50.1': resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.46.2': resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.50.1': resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.46.2': resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-linux-x64-musl@4.50.1': resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.50.1': resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==} @@ -2366,24 +2433,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.14': resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.14': resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.14': resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.14': resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==} @@ -2980,6 +3051,11 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@typescript/vfs@1.6.1': + resolution: {integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==} + peerDependencies: + typescript: '*' + '@vis.gl/react-mapbox@8.1.0': resolution: {integrity: sha512-FwvH822oxEjWYOr+pP2L8hpv+7cZB2UsQbHHHT0ryrkvvqzmTgt7qHDhamv0EobKw86e1I+B4ojENdJ5G5BkyQ==} peerDependencies: @@ -3047,6 +3123,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -3055,6 +3135,10 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + ansis@4.1.0: resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} engines: {node: '>=14'} @@ -3322,6 +3406,10 @@ packages: cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} @@ -3471,6 +3559,9 @@ packages: earcut@3.0.2: resolution: {integrity: sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -3485,6 +3576,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -3614,6 +3708,10 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -3697,6 +3795,11 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3950,10 +4053,17 @@ packages: resolution: {integrity: sha512-DelDWWoa3mBoyWTq3wjp+GIWx/yZdN7zLUE7NFhKjAiJ+uJVRkbLlwykdduCE4sPUUy8mlTYTmdhBUYu91F+sw==} engines: {node: '>=18'} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + jake@10.9.4: resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} engines: {node: '>=10'} @@ -4054,24 +4164,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} @@ -4104,6 +4218,10 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4148,6 +4266,10 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4236,6 +4358,9 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -4246,9 +4371,17 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + pathe@0.2.0: resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} @@ -4528,6 +4661,11 @@ packages: rfc4648@1.5.4: resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==} + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + robust-predicates@2.0.4: resolution: {integrity: sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==} @@ -4643,6 +4781,14 @@ packages: resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} engines: {node: '>=0.10.0'} + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -4662,6 +4808,10 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + simple-git-hooks@2.13.1: resolution: {integrity: sha512-WszCLXwT4h2k1ufIXAgsbiTOazqqevFCIncOuUBZJ91DdvWcC5+OFkluWRQPrcuSYd8fjq+o2y1QfWqYMoAToQ==} hasBin: true @@ -4743,6 +4893,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} @@ -4773,6 +4927,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + strip-comments@2.0.1: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} @@ -4967,6 +5125,11 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typescript@4.5.2: + resolution: {integrity: sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==} + engines: {node: '>=4.2.0'} + hasBin: true + typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} @@ -5238,6 +5401,11 @@ packages: resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -5296,6 +5464,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5458,16 +5630,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.0)': + '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.4 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.3.1 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.0)': + '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.1 @@ -5516,9 +5701,9 @@ snapshots: '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.0)': + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 '@babel/traverse': 7.28.4 @@ -5534,6 +5719,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: '@babel/traverse': 7.28.4 @@ -5569,53 +5763,53 @@ snapshots: dependencies: '@babel/types': 7.28.4 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.0)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.0)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': @@ -5628,168 +5822,168 @@ snapshots: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.0)': + '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.0) + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.0) + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.0)': + '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.0)': + '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.0)': + '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.0)': + '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.0)': + '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -5802,102 +5996,110 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.0)': + '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.0) + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.0)': + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.0) + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': @@ -5910,48 +6112,48 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.0)': + '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.0)': @@ -5965,108 +6167,108 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/preset-env@7.28.3(@babel/core@7.28.0)': + '@babel/preset-env@7.28.3(@babel/core@7.28.4)': dependencies: '@babel/compat-data': 7.28.4 - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.0) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.0) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.0) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.0) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.0) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.0) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.0) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.0) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.0) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.0) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.0) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.0) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.0) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.0) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.4) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.4) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.4) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.4) + '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) + '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.4) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.4) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) core-js-compat: 3.45.1 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.4)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/types': 7.28.4 esutils: 2.0.3 @@ -6144,7 +6346,25 @@ snapshots: '@biomejs/cli-win32-x64@2.2.4': optional: true - '@bufbuild/protobuf@2.8.0': {} + '@bufbuild/protobuf@1.10.1': {} + + '@bufbuild/protobuf@2.9.0': {} + + '@bufbuild/protoc-gen-es@1.10.1(@bufbuild/protobuf@1.10.1)': + dependencies: + '@bufbuild/protoplugin': 1.10.1 + optionalDependencies: + '@bufbuild/protobuf': 1.10.1 + transitivePeerDependencies: + - supports-color + + '@bufbuild/protoplugin@1.10.1': + dependencies: + '@bufbuild/protobuf': 1.10.1 + '@typescript/vfs': 1.6.1(typescript@4.5.2) + typescript: 4.5.2 + transitivePeerDependencies: + - supports-color '@emnapi/core@1.5.0': dependencies: @@ -6344,6 +6564,21 @@ snapshots: '@standard-schema/utils': 0.3.0 react-hook-form: 7.64.0(react@19.2.0) + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 @@ -6381,7 +6616,7 @@ snapshots: '@jsr/meshtastic__protobufs@2.7.8': dependencies: - '@bufbuild/protobuf': 2.8.0 + '@bufbuild/protobuf': 2.9.0 '@mapbox/geojson-rewind@0.5.2': dependencies: @@ -7061,9 +7296,9 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.42': {} - '@rollup/plugin-babel@5.3.1(@babel/core@7.28.0)(@types/babel__core@7.20.5)(rollup@2.79.2)': + '@rollup/plugin-babel@5.3.1(@babel/core@7.28.4)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.28.4 '@babel/helper-module-imports': 7.27.1 '@rollup/pluginutils': 3.1.0(rollup@2.79.2) rollup: 2.79.2 @@ -8777,6 +9012,13 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} + '@typescript/vfs@1.6.1(typescript@4.5.2)': + dependencies: + debug: 4.4.1 + typescript: 4.5.2 + transitivePeerDependencies: + - supports-color + '@vis.gl/react-mapbox@8.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: react: 19.2.0 @@ -8863,12 +9105,16 @@ snapshots: ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + ansis@4.1.0: {} ansis@4.2.0: {} @@ -8947,27 +9193,27 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.0): + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): dependencies: '@babel/compat-data': 7.28.4 - '@babel/core': 7.28.0 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.0): + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.4): dependencies: - '@babel/core': 7.28.0 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) core-js-compat: 3.45.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.0): + babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.4): dependencies: - '@babel/core': 7.28.0 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color @@ -9152,6 +9398,12 @@ snapshots: transitivePeerDependencies: - encoding + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + crypto-random-string@2.0.0: {} crypto-random-string@5.0.0: @@ -9284,6 +9536,8 @@ snapshots: earcut@3.0.2: {} + eastasianwidth@0.2.0: {} + ejs@3.1.10: dependencies: jake: 10.9.4 @@ -9294,6 +9548,8 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + empathic@2.0.0: {} end-of-stream@1.4.5: @@ -9508,6 +9764,11 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + fraction.js@4.3.7: {} fs-extra@10.1.0: @@ -9597,6 +9858,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -9845,8 +10115,14 @@ snapshots: isbot@5.1.29: {} + isexe@2.0.0: {} + isobject@3.0.1: {} + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + jake@10.9.4: dependencies: async: 3.2.6 @@ -9954,6 +10230,8 @@ snapshots: dependencies: tslib: 2.8.1 + lru-cache@11.2.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -10014,6 +10292,10 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -10089,6 +10371,8 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + package-json-from-dist@1.0.1: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -10101,8 +10385,15 @@ snapshots: path-is-absolute@1.0.1: {} + path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@2.0.0: + dependencies: + lru-cache: 11.2.2 + minipass: 7.1.2 + pathe@0.2.0: {} pathe@2.0.3: {} @@ -10364,6 +10655,11 @@ snapshots: rfc4648@1.5.4: {} + rimraf@6.0.1: + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + robust-predicates@2.0.4: {} robust-predicates@3.0.2: {} @@ -10560,6 +10856,12 @@ snapshots: is-plain-object: 2.0.4 split-string: 3.1.0 + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -10590,6 +10892,8 @@ snapshots: siginfo@2.0.0: {} + signal-exit@4.1.0: {} + simple-git-hooks@2.13.1: {} simple-zstd@1.4.2: @@ -10662,6 +10966,12 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 @@ -10719,6 +11029,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + strip-comments@2.0.1: {} strip-indent@3.0.0: @@ -10919,6 +11233,8 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript@4.5.2: {} + typescript@5.9.2: {} typescript@5.9.3: {} @@ -11293,6 +11609,10 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 + which@2.0.2: + dependencies: + isexe: 2.0.0 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -11310,10 +11630,10 @@ snapshots: workbox-build@7.3.0(@types/babel__core@7.20.5): dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1) - '@babel/core': 7.28.0 - '@babel/preset-env': 7.28.3(@babel/core@7.28.0) + '@babel/core': 7.28.4 + '@babel/preset-env': 7.28.3(@babel/core@7.28.4) '@babel/runtime': 7.28.4 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.0)(@types/babel__core@7.20.5)(rollup@2.79.2) + '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.4)(@types/babel__core@7.20.5)(rollup@2.79.2) '@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2) '@rollup/plugin-replace': 2.4.2(rollup@2.79.2) '@rollup/plugin-terser': 0.4.4(rollup@2.79.2) @@ -11417,6 +11737,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + wrappy@1.0.2: {} xtend@4.0.2: {}