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
+
+[](https://github.com/meshtastic/protobufs/actions/workflows/ci.yml)
+[](https://cla-assistant.io/meshtastic/protobufs)
+[](https://opencollective.com/meshtastic/)
+[](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
+
+
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
+
+[](https://github.com/meshtastic/protobufs/actions/workflows/ci.yml)
+[](https://cla-assistant.io/meshtastic/protobufs)
+[](https://opencollective.com/meshtastic/)
+[](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
+
+
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: {}